@vcp-dev/site-edit-bridge 0.6.10 → 0.7.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.
package/dist/server.js CHANGED
@@ -1,4 +1,4 @@
1
- import X from"node:http";import{createHash as F,randomBytes as Z,timingSafeEqual as ee}from"node:crypto";import C from"node:path";import{WebSocket as U,WebSocketServer as te}from"ws";import{createPreviewSiteEditEngineRuntime as se,openFileHistoryStore as ne}from"@vcp-dev/site-edit-engine";import{resolveNextAppRouteId as ie,scanNextAppRouterRoutes as oe}from"@vcp-dev/site-edit-engine/next-app-router";import{SiteEditSourceWatcher as re}from"@vcp-dev/site-edit-engine/source-watcher";function I(t){let e=new Map,s=[],n=new Map,i=[],o=t.pageComposition.status==="supported"?t.pageComposition.placementUnitKeys:[],r=new Map(o.map((a,u)=>[a,u])),p=t.pageComposition.status==="supported"?{status:"supported",containerKey:t.pageComposition.containerKey,hasBusinessMembers:t.pageComposition.hasBusinessMembers,placementUnitKeys:t.pageComposition.placementUnitKeys,placements:t.pageComposition.placements.map(a=>({placementKey:a.placementKey,placementUnitKey:a.placementUnitKey,relation:a.relation}))}:{status:"unsupported",reason:t.pageComposition.reason,diagnostics:t.pageComposition.diagnostics},h=t.entries.flatMap((a,u)=>a.dynamicDataSummary?[[u,a.dynamicDataSummary]]:[]),y=a=>{let u=e.get(a);if(typeof u=="number")return u;let l=s.length;return s.push(a),e.set(a,l),l},$=a=>{let u=null;for(let l of z(a)){let E=`${u??"root"}\0${l}`,_=n.get(E);if(typeof _=="number"){u=_;continue}let T=i.length;i.push([u,y(l)]),n.set(E,T),u=T}if(u===null)throw new Error("Document key must not be empty");return u};return{encoding:"segment-trie-v1",siteId:t.siteId,snapshotId:t.snapshotId,routeId:t.routeId,version:t.version,pageComposition:p,tokens:s,nodes:i,entries:t.entries.map(a=>{let u=a.pageCompositionUnitKey?r.get(a.pageCompositionUnitKey)??-1:-1;if(a.pageCompositionUnitKey&&u<0)throw new Error(`Render entry ${a.key} references unknown page composition unit ${a.pageCompositionUnitKey}`);return[$(a.key),W(a.operationSummary),...u>=0?[u]:[]]}),...h.length>0?{dynamicDataSummaries:h}:{}}}function W(t){return(t.canUpdateText?1:0)|(t.canInsertChild?2:0)|(t.canMove?4:0)|(t.canRemove?8:0)}function z(t){if(!t)return[];let e=[],s=0,n=B(t,s);if(n<0)return e.push(t),e;for(e.push(t.slice(0,n)),s=n;s<t.length;){if(n=B(t,s+(t.startsWith("::",s)?2:1)),n<0){e.push(t.slice(s));break}e.push(t.slice(s,n)),s=n}return e}function B(t,e){let s=t.indexOf("/",e),n=t.indexOf("::",e);return s<0?n:n<0?s:Math.min(s,n)}var d=class t{constructor(){}static parseMessage(e,s={}){let n=JSON.parse(e);if(!t.isMessage(n,s))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 s=e.payload,n=typeof s.id=="string"?s.id:"unknown",i=t.isRequestKind(s.kind)?s.kind:"get-document";return{id:n,kind:i}}return{id:"unknown",kind:"get-document"}}static isRequestKind(e){return e==="initialize-session"||e==="get-document"||e==="get-history-status"||e==="get-style-context"||e==="get-object-edit-context"||e==="get-class-name-source"||e==="get-source-tree"||e==="get-source-file"||e==="resolve-source-location"||e==="execute"||e==="undo"||e==="redo"}static isMessage(e,s={}){return!c(e)||typeof e.type!="string"?!1:e.type==="request"?t.isRequestPayload(e.payload,s):e.type==="response"||e.type==="error"?c(e.payload)&&typeof e.payload.id=="string":e.type==="event"?c(e.payload)&&c(e.payload.event):e.type==="auth"?c(e.payload)&&typeof e.payload.key=="string":e.type==="auth-ok"?c(e.payload)&&e.payload.ok===!0:!1}static isRequestPayload(e,s={}){if(!c(e)||typeof e.id!="string"||!t.isRequestKind(e.kind))return!1;switch(e.kind){case"initialize-session":return typeof e.routeId=="string"&&(e.mutationContext===void 0||R(e.mutationContext));case"get-document":case"get-style-context":return typeof e.routeId=="string";case"get-object-edit-context":case"get-class-name-source":case"resolve-source-location":return typeof e.key=="string"&&(e.routeId===void 0||typeof e.routeId=="string");case"get-history-status":return e.mutationContext===void 0;case"get-source-tree":return!0;case"get-source-file":return typeof e.path=="string";case"execute":return Q(e.request)&&(e.request.mutationContext===void 0||R(e.request.mutationContext))&&(s.validateOperationRequest?.(e.request)??!0);case"undo":case"redo":return e.mutationContext===void 0||R(e.mutationContext)}}},g=class{constructor(e){this.options=e,this.messageQueue=new w,this.eventDispatcher=new S(s=>{this.sendJson(s)}),this.unsubscribe=e.engine.subscribe(s=>{this.eventDispatcher.push(s)}),e.socket.onmessage=s=>{try{this.messageQueue.enqueue(()=>this.handleRawMessage(s.data))}catch(n){this.sendJson({type:"error",payload:{id:"unknown",kind:"get-document",message:n instanceof Error?n.message:"Bridge queue overflow"}}),e.socket.close(1013,"bridge busy")}},e.socket.onclose=()=>{this.unsubscribe()}}async handleMessage(e){try{let s=e;if(s.type!=="request")return;let n=s.payload,{id:i}=n;switch(n.kind){case"initialize-session":{let o=await this.options.engine.initializeSession({routeId:n.routeId,...n.mutationContext?{mutationContext:n.mutationContext}:{}});this.sendJson({type:"response",payload:{id:i,kind:n.kind,result:{ok:!0,data:{document:I(o.data.document),historyStatus:o.data.historyStatus}}}});return}case"get-document":this.sendJson({type:"response",payload:{id:i,kind:n.kind,result:{ok:!0,data:I((await this.options.engine.getDocument(n.routeId)).data)}}});return;case"get-history-status":this.sendJson({type:"response",payload:{id:i,kind:n.kind,result:await this.options.engine.getHistoryStatus()}});return;case"get-style-context":this.sendJson({type:"response",payload:{id:i,kind:n.kind,result:await this.options.engine.getStyleContext(n.routeId)}});return;case"get-object-edit-context":this.sendJson({type:"response",payload:{id:i,kind:n.kind,result:await this.options.engine.getObjectEditContext(n.key,n.routeId)}});return;case"get-class-name-source":this.sendJson({type:"response",payload:{id:i,kind:n.kind,result:await this.options.engine.getClassNameSource(n.key,n.routeId)}});return;case"get-source-tree":this.sendJson({type:"response",payload:{id:i,kind:n.kind,result:await this.options.engine.getSourceTree()}});return;case"get-source-file":this.sendJson({type:"response",payload:{id:i,kind:n.kind,result:await this.options.engine.getSourceFile({path:n.path})}});return;case"resolve-source-location":this.sendJson({type:"response",payload:{id:i,kind:n.kind,result:await this.options.engine.resolveSourceLocation({key:n.key,routeId:n.routeId})}});return;case"execute":{await this.handleBufferedOperation(i,n.kind,()=>this.options.engine.execute(n.request));return}case"undo":await this.handleBufferedOperation(i,n.kind,()=>this.options.engine.undo());return;case"redo":await this.handleBufferedOperation(i,n.kind,()=>this.options.engine.redo());return}}catch(s){let n=d.extractRequestInfo(e);this.sendJson({type:"error",payload:{...n,message:H(s),code:D(s)}})}}async handleRawMessage(e){try{await this.handleMessage(d.parseMessage(e,{validateOperationRequest:this.options.validateOperationRequest}))}catch(s){let n=s instanceof Error?s.message:"Invalid websocket message",i=Y(e);this.sendJson({type:"error",payload:{...i,message:n}})}}sendJson(e){this.options.socket.send(d.stringifyMessage(e))}async handleBufferedOperation(e,s,n){this.eventDispatcher.beginBuffering();try{let i=await n();this.sendJson({type:"response",payload:{id:e,kind:s,result:i}}),this.eventDispatcher.flush()}catch(i){this.sendJson({type:"error",payload:{id:e,kind:s,message:H(i),code:D(i)}}),this.eventDispatcher.flush()}}},S=class{constructor(e){this.send=e,this.bufferedEvents=null}push(e){let s={type:"event",payload:{event:e}};if(this.bufferedEvents){this.bufferedEvents.push(s);return}this.send(s)}beginBuffering(){this.bufferedEvents=[]}flush(){let e=this.bufferedEvents??[];this.bufferedEvents=null,e.forEach(s=>{this.send(s)})}},w=class{constructor(e=64){this.maxQueued=e,this.queue=Promise.resolve(),this.queued=0}enqueue(e){if(this.queued>=this.maxQueued)throw new Error("Bridge request queue is full");this.queued+=1;let s=async()=>{this.queued-=1,await e()},n=this.queue.then(s,s);return this.queue=n.then(()=>{},()=>{}),n}};function c(t){return typeof t=="object"&&t!==null}function Q(t){return c(t)&&typeof t.id=="string"&&typeof t.siteId=="string"&&typeof t.baseSnapshotId=="string"&&(t.routeId===void 0||typeof t.routeId=="string")&&typeof t.kind=="string"&&c(t.target)&&typeof t.documentVersion=="number"&&Number.isInteger(t.documentVersion)&&t.documentVersion>=0&&c(t.params)}function R(t){return G(t)}function D(t){if(!t||typeof t!="object")return;let e=t.code;return typeof e=="string"&&e.length>0?e:void 0}function H(t){if(t instanceof Error)return t.message;if(!t||typeof t!="object")return"Unknown websocket operation failure";let e=t.message;return typeof e=="string"&&e.length>0?e:"Unknown websocket operation failure"}function G(t){return c(t)?typeof t.editingSessionId=="string"&&t.editingSessionId.length>0&&typeof t.lockId=="string"&&t.lockId.length>0&&typeof t.ownerId=="string"&&t.ownerId.length>0&&typeof t.leaseAssertion=="string"&&t.leaseAssertion.length>0:!1}function Y(t){try{return d.extractRequestInfo(JSON.parse(t))}catch{return{id:"unknown",kind:"get-document"}}}var f=class{constructor(){this.tail=Promise.resolve()}run(e){let s=this.tail.then(e,e);return this.tail=s.then(()=>{},()=>{}),s}};import{SiteEditOperationRequestSchema as ae}from"@vcp-dev/contracts";var ue="127.0.0.1",ce=30218,de="/__vcp/site-edit/bridge",P=6*1024*1024,he=P*2,pe=3e3,M=50,O="__VCP_SITE_EDIT_BRIDGE_SERVERS__";function Ae(t){let e=q(t),s=J(e),n=j(),i=n.get(s);if(i)return i;let o=new m(e);n.set(s,o);try{o.start()}catch(r){throw n.delete(s),o.stop(),r}return o}function Ke(t,e,s={}){let n=new m(q(e),t,!1,s);return n.start({listen:!1}),n}var m=class{constructor(e,s=X.createServer((o,r)=>{r.writeHead(404),r.end("VCP site edit bridge server")}),n=!0,i={}){this.options=e,this.server=s,this.closeHttpServerOnStop=n,this.dependencies=i,this.runtime=null,this.activeHistorySessionId=null,this.historySessionTransition=Promise.resolve(),this.mutationQueue=new f,this.eventListeners=new Set,this.routes=[],this.stopWatching=null,this.stopWebSocketServer=null,this.pendingChangedFiles=new Set,this.fileChangeTimer=null,this.isStarted=!1,this.runtimeVersionFloor=0,this.activeHistoryStore=null,this.versionPersistence=Promise.resolve()}start(e={}){if(this.isStarted)return;this.refreshRoutes(),this.isStarted=!0,this.createRuntime();let s=ge({server:this.server,path:this.options.path,sessionKey:this.options.sessionKey,host:this.options.host,allowedOrigins:this.options.allowedOrigins,engine:this.createBridgeEngine()});this.stopWebSocketServer=s.stop,this.stopWatching=new re({projectRoot:this.options.projectRoot,watch_dirs:this.options.runtime.watch_dirs,interval_ms:this.options.runtime.watch_interval_ms,debounce_ms:this.options.runtime.watch_debounce_ms??M,max_dirs:this.options.runtime.watch_max_dirs,max_files:this.options.runtime.watch_max_files,max_depth:this.options.runtime.watch_max_depth,max_startup_ms:this.options.runtime.watch_max_startup_ms,on_change:n=>this.handleFileChanged(n),on_batch_change:n=>this.handleFilesChanged(n)}).start(),e.listen!==!1&&this.server.listen(this.options.port,this.options.host)}getHealth(){let e=!!this.runtime;return{ok:this.isStarted&&e,bridgePath:this.options.path,runtimeReady:e,routesIndexed:this.routes.length,sessionRequired:!!this.options.sessionKey}}stop(){this.stopWatching?.(),this.stopWatching=null,this.flushChangedFiles(),this.fileChangeTimer&&(clearTimeout(this.fileChangeTimer),this.fileChangeTimer=null),this.stopWebSocketServer?.(),this.stopWebSocketServer=null,this.runtime?.dispose(),this.runtime=null,this.closeHttpServerOnStop&&this.server.close();let e=j(),s=J(this.options);e.get(s)===this&&e.delete(s),this.isStarted=!1}createRuntime(e,s=null){let n=this.runtime;this.activeHistoryStore=e??null;let i=(this.dependencies.createRuntime??se)({...this.options.tenantId?{tenantId:this.options.tenantId}:{},siteId:this.options.siteId,snapshotId:this.options.snapshotId,projectRoot:this.options.projectRoot,routes:this.routes,onEvent:o=>{"version"in o&&typeof o.version=="number"&&this.recordRuntimeVersion(o.version);for(let r of this.eventListeners)r(o)},...e?{historyStore:e}:{},initialDocumentVersion:this.runtimeVersionFloor});this.runtime=i,this.activeHistorySessionId=s,n?.dispose()}createBridgeEngine(){return{initializeSession:e=>this.mutationQueue.run(async()=>{let s=await this.bindHistorySession(this.options.snapshotId);if(!s.ok)throw new Error(`${s.code}: ${s.message}`);let{runtime:n,resolvedRouteId:i}=await this.activateRoute(e.routeId),o=n.getDocument(i).data;await this.recordRuntimeVersion(o.version);let r=(await n.getHistoryStatus()).data;return{ok:!0,data:{document:o,historyStatus:r}}}),getDocument:async e=>{let{runtime:s,resolvedRouteId:n}=await this.activateRoute(e),i=s.getDocument(n);return await this.recordRuntimeVersion(i.data.version),i},getHistoryStatus:async()=>this.getRuntime().getHistoryStatus(),getStyleContext:async e=>{let{runtime:s,resolvedRouteId:n}=await this.activateRoute(e);return s.getStyleContext(n)},getObjectEditContext:async(e,s)=>this.getRuntime().getObjectEditContext(e,s?this.resolveRouteId(s):void 0),getClassNameSource:async(e,s)=>{let n=this.getRuntime(),i=s?this.resolveRouteId(s):void 0;return n.getClassNameSource(e,i)},getSourceTree:async()=>this.getRuntime().getSourceTree(),getSourceFile:async e=>this.getRuntime().getSourceFile(e),resolveSourceLocation:async e=>this.getRuntime().resolveSourceLocation({key:e.key,routeId:e.routeId?this.resolveRouteId(e.routeId):void 0}),execute:(e,s)=>this.mutationQueue.run(async()=>{let n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)return k(n,e);let i=await this.getRuntime().executeOperation(this.normalizeRequest(e));return i.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(i.data.resultVersion),i}),undo:()=>this.mutationQueue.run(async()=>{let e=await this.bindHistorySession(this.options.snapshotId);if(!e.ok)return k(e);let s=await this.getRuntime().undo();return s.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(s.data.resultVersion),s}),redo:()=>this.mutationQueue.run(async()=>{let e=await this.bindHistorySession(this.options.snapshotId);if(!e.ok)return k(e);let s=await this.getRuntime().redo();return s.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(s.data.resultVersion),s}),subscribe:e=>(this.eventListeners.add(e),()=>this.eventListeners.delete(e))}}async bindHistorySession(e){if(!this.options.historyRoot)return{ok:!1,code:"RECOVERY_PERSIST_FAILED",message:"Durable edit history is not configured."};if(this.activeHistorySessionId===e)return{ok:!0};let s=this.historySessionTransition.then(async()=>{if(this.activeHistorySessionId===e)return;let n=await(this.dependencies.openHistoryStore??ne)(le({root:this.options.historyRoot,siteId:this.options.siteId,snapshotId:this.options.snapshotId,editingSessionId:e}));if(!this.isStarted)return;let i=n.readDocumentVersion?await n.readDocumentVersion():0;this.runtimeVersionFloor=Math.max(this.runtimeVersionFloor,i),this.createRuntime(n,e)});this.historySessionTransition=s.catch(()=>{});try{return await s,{ok:!0}}catch{return{ok:!1,code:"RECOVERY_PERSIST_FAILED",message:"Durable edit history could not be opened."}}}recordRuntimeVersion(e){this.runtimeVersionFloor=Math.max(this.runtimeVersionFloor,e);let s=this.activeHistoryStore;return s?.writeDocumentVersion?(this.versionPersistence=this.versionPersistence.then(()=>s.writeDocumentVersion(this.runtimeVersionFloor)).catch(()=>{}),this.versionPersistence):Promise.resolve()}async activateRoute(e){let s=this.getRuntime(),n=this.resolveRouteId(e);return await s.setActiveRoute(n),{runtime:s,resolvedRouteId:n}}normalizeRequest(e){return e.target.kind!=="route"?e.routeId?{...e,routeId:this.resolveRouteId(e.routeId)}:e:{...e,target:{...e.target,routeId:this.resolveRouteId(e.target.routeId)}}}handleFileChanged(e){this.handleFilesChanged([e])}handleFilesChanged(e){for(let n of e)this.pendingChangedFiles.add(n);this.fileChangeTimer&&clearTimeout(this.fileChangeTimer);let s=this.options.runtime.watch_debounce_ms??M;this.fileChangeTimer=setTimeout(()=>{this.fileChangeTimer=null,this.flushChangedFiles()},s),this.fileChangeTimer?.unref?.()}flushChangedFiles(){if(this.fileChangeTimer&&(clearTimeout(this.fileChangeTimer),this.fileChangeTimer=null),this.pendingChangedFiles.size===0)return;let e=[...this.pendingChangedFiles].sort((s,n)=>s.localeCompare(n));this.pendingChangedFiles.clear(),this.refreshRoutes();for(let s of e)this.runtime?.notifyFileChanged(s)}refreshRoutes(){let e=this.options.runtime.routes?.length?this.options.runtime.routes:oe(this.options.projectRoot),s=new Map(this.routes.map(i=>[i.routeId,i.entryFile])),n=new Set(e.map(i=>i.routeId));this.routes=e;for(let i of e)s.get(i.routeId)!==i.entryFile&&this.runtime?.registerRoute(i.routeId,i.entryFile);for(let i of s.keys())n.has(i)||this.runtime?.unregisterRoute(i)}resolveRouteId(e){let s=ie(e,this.routes,this.options.basePath);if(!s)throw new Error(`Route is not indexed by the preview bridge: ${e}`);return s}getRuntime(){if(!this.runtime)throw new Error("VCP site edit preview bridge runtime is not ready");return this.runtime}};function q(t){return{tenantId:t.tenantId,siteId:t.siteId,snapshotId:t.snapshotId,projectRoot:C.resolve(t.projectRoot??process.cwd()),basePath:t.basePath??"",host:t.host??ue,port:t.port??ce,path:t.path??de,sessionKey:t.sessionKey??we(),historyRoot:t.historyRoot,allowedOrigins:t.allowedOrigins??[],runtime:t.runtime??{}}}function le(t){return C.join(C.resolve(t.root),V(t.siteId),V(t.snapshotId),F("sha256").update(t.editingSessionId).digest("hex").slice(0,32))}function V(t){return/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(t)&&t!=="."&&t!==".."?t:F("sha256").update(t).digest("hex").slice(0,32)}function j(){let t=globalThis;return t[O]??=new Map,t[O]}function J(t){return`${t.projectRoot}:${t.host}:${t.port}:${t.path}:${t.historyRoot??""}`}function k(t,e){return{ok:!1,error:{code:t.code,message:t.message},data:{requestId:e?.id??"mutation-context",kind:e?.kind??"update-text",target:e?.target??{kind:"node",key:""},resultVersion:e?.documentVersion??0}}}function ge(t){let e=new te({maxPayload:P,noServer:!0}),s=new WeakSet,n=o=>{new g({socket:new b(o),engine:t.engine,validateOperationRequest:r=>ae.safeParse(r).success})},i=(o,r,p)=>{if(!fe(o,t))return;let h=me(o,t);if(!h){r.write(`HTTP/1.1 401 Unauthorized\r
1
+ import me from"node:http";import A from"node:fs";import{createHash as Y,randomBytes as fe,timingSafeEqual as ge}from"node:crypto";import g from"node:path";import{WebSocket as Z,WebSocketServer as ye}from"ws";import{createPreviewSiteEditEngineRuntime as Ie,openFileHistoryStore as Se,resolveManagedPageTemplateComposition as we,scanSiteEditCompositionsFromFiles as Ce}from"@vcp-dev/site-edit-engine";import{resolveNextAppRouteId as xe,scanNextAppRouterRoutesFromFiles as Re}from"@vcp-dev/site-edit-engine/next-app-router";import{SiteEditSourceWatcher as Ee}from"@vcp-dev/site-edit-engine/source-watcher";function U(t){let e=new Map,s=[],i=new Map,o=[],n=t.pageComposition.status==="supported"?t.pageComposition.placementUnitKeys:[],r=new Map(n.map((u,h)=>[u,h])),a=t.pageComposition.status==="supported"?{status:"supported",containerKey:t.pageComposition.containerKey,hasBusinessMembers:t.pageComposition.hasBusinessMembers,placementUnitKeys:t.pageComposition.placementUnitKeys,placements:t.pageComposition.placements.map(u=>({placementKey:u.placementKey,placementUnitKey:u.placementUnitKey,relation:u.relation}))}:{status:"unsupported",reason:t.pageComposition.reason,diagnostics:t.pageComposition.diagnostics},c=t.entries.flatMap((u,h)=>u.dynamicDataSummary?[[h,u.dynamicDataSummary]]:[]),p=u=>{let h=e.get(u);if(typeof h=="number")return h;let C=s.length;return s.push(u),e.set(u,C),C},y=u=>{let h=null;for(let C of re(u)){let H=`${h??"root"}\0${C}`,V=i.get(H);if(typeof V=="number"){h=V;continue}let P=o.length;o.push([h,p(C)]),i.set(H,P),h=P}if(h===null)throw new Error("Document key must not be empty");return h};return{encoding:"segment-trie-v1",siteId:t.siteId,snapshotId:t.snapshotId,composition:{...t.composition},routeId:t.composition.routeId,version:t.version,pageComposition:a,tokens:s,nodes:o,entries:t.entries.map(u=>{let h=u.pageCompositionUnitKey?r.get(u.pageCompositionUnitKey)??-1:-1;if(u.pageCompositionUnitKey&&h<0)throw new Error(`Render entry ${u.key} references unknown page composition unit ${u.pageCompositionUnitKey}`);return[y(u.key),oe(u.operationSummary),...h>=0?[h]:[]]}),...c.length>0?{dynamicDataSummaries:c}:{}}}function oe(t){return(t.canUpdateText?1:0)|(t.canInsertChild?2:0)|(t.canMove?4:0)|(t.canRemove?8:0)}function re(t){if(!t)return[];let e=[],s=0,i=N(t,s);if(i<0)return e.push(t),e;for(e.push(t.slice(0,i)),s=i;s<t.length;){if(i=N(t,s+(t.startsWith("::",s)?2:1)),i<0){e.push(t.slice(s));break}e.push(t.slice(s,i)),s=i}return e}function N(t,e){let s=t.indexOf("/",e),i=t.indexOf("::",e);return s<0?i:i<0?s:Math.min(s,i)}var W="SITE_EDIT_COMPOSITION_SESSION_MISMATCH",M="SITE_EDIT_COMPOSITION_SESSION_REQUIRED";var l=class t{constructor(){}static parseMessage(e,s={}){let i=JSON.parse(e);if(!t.isMessage(i,s))throw new Error("Invalid site edit bridge message");return i}static stringifyMessage(e){return JSON.stringify(e)}static extractRequestInfo(e){if(d(e)&&d(e.payload)){let s=typeof e.payload.id=="string"?e.payload.id:"unknown",i=this.isRequestKind(e.payload.kind)?e.payload.kind:"get-document";return{id:s,kind:i}}return{id:"unknown",kind:"get-document"}}static isRequestKind(e){return e==="initialize-session"||e==="get-document"||e==="get-history-status"||e==="get-style-context"||e==="get-object-edit-context"||e==="get-class-name-source"||e==="get-source-tree"||e==="get-source-file"||e==="resolve-source-location"||e==="execute"||e==="undo"||e==="redo"}static isMessage(e,s={}){return!d(e)||typeof e.type!="string"?!1:e.type==="request"?ae(e.payload,s):e.type==="response"||e.type==="error"?d(e.payload)&&typeof e.payload.id=="string":e.type==="event"?d(e.payload)&&d(e.payload.event):e.type==="auth"?d(e.payload)&&typeof e.payload.key=="string":e.type==="auth-ok"&&d(e.payload)&&e.payload.ok===!0}},R=class{constructor(e){this.options=e,this.session={subscribedCompositionKeys:new Set},this.messageQueue=new D,this.eventDispatcher=new O(s=>{this.sendJson(s)}),this.unsubscribe=e.engine.subscribe(s=>{this.handleEngineEvent(s)}),e.socket.onmessage=s=>{try{this.messageQueue.enqueue(()=>this.handleRawMessage(s.data))}catch(i){this.sendJson({type:"error",payload:{id:"unknown",kind:"get-document",message:i instanceof Error?i.message:"Bridge queue overflow"}}),e.socket.close(1013,"bridge busy")}},e.socket.onclose=()=>{this.unsubscribe(),this.session.activeComposition=void 0,this.session.subscribedCompositionKeys.clear()}}async handleMessage(e){try{let s=e;if(s.type!=="request")return;let i=s.payload,{id:o}=i;switch(i.kind){case"initialize-session":{let n=v(i),r=await this.resolve(n),a=await this.options.engine.initializeSession({composition:r.context,...i.mutationContext?{mutationContext:i.mutationContext}:{}});this.activateSession(r.context),this.sendJson({type:"response",payload:{id:o,kind:i.kind,result:f({...a,data:{...a.data,document:z(a.data.document)}},r.context)}});return}case"get-document":{let n=await this.resolveWireContext(i),r=await this.options.engine.getDocument(n);this.sendResult(o,i.kind,pe(r,n));return}case"get-history-status":{let n=await this.resolveWireContext(i),r=await this.options.engine.getHistoryStatus(n);this.sendResult(o,i.kind,f(r,n));return}case"get-style-context":{let n=await this.resolveWireContext(i);this.sendResult(o,i.kind,f(await this.options.engine.getStyleContext(n),n));return}case"get-object-edit-context":{let n=await this.resolveWireContext(i);this.sendResult(o,i.kind,f(await this.options.engine.getObjectEditContext(i.key,n),n));return}case"get-class-name-source":{let n=await this.resolveWireContext(i);this.sendResult(o,i.kind,f(await this.options.engine.getClassNameSource(i.key,n),n));return}case"get-source-tree":{let n=await this.resolveWireContext(i);this.sendResult(o,i.kind,f(await this.options.engine.getSourceTree(n),n));return}case"get-source-file":{let n=await this.resolveWireContext(i);this.sendResult(o,i.kind,f(await this.options.engine.getSourceFile({path:i.path,composition:n}),n));return}case"resolve-source-location":{let n=await this.resolveWireContext(i),r=f(await this.options.engine.resolveSourceLocation({key:i.key,composition:n}),n);this.sendResult(o,i.kind,r);return}case"execute":{let n=await this.resolveOperationWireContext(i.request),r=await this.resolveWireContext(i);if(I(n)!==I(r))throw new S(W,"The execute request composition does not match its operation composition.");let a=await this.normalizeOperationRequest(i.request,n);await this.handleBufferedOperation(o,i.kind,()=>this.options.engine.execute(a));return}case"undo":case"redo":{let n=await this.resolveWireContext(i);await this.handleBufferedOperation(o,i.kind,()=>i.kind==="undo"?this.options.engine.undo(n):this.options.engine.redo(n));return}}}catch(s){let i=l.extractRequestInfo(e);this.sendJson({type:"error",payload:{...i,message:T(s),code:_(s)}})}}async resolve(e){return this.options.engine.resolveComposition(e)}async resolveAndAssert(e){let s=await this.resolve(e),i=this.session.activeComposition;if(!i)throw new S(M,"Initialize a composition session before issuing this request.");if(I(i)!==I(s.context))throw new S(W,"The request composition does not match the active socket session.");return s.context}async resolveWireContext(e){let s=v(e);return this.resolveAndAssert(s)}async resolveOperationWireContext(e){let s=de(e);return this.resolveAndAssert(s)}activateSession(e){this.session.activeComposition=e,this.session.subscribedCompositionKeys.clear(),this.session.subscribedCompositionKeys.add(I(e))}async normalizeOperationRequest(e,s){let i={...e,composition:j(s)};if(i.target.kind==="route"){let o=i.target,n=v(o),r=await this.resolveAndAssert(n);i.target={...o,composition:j(r)}}return i}handleEngineEvent(e){let s=e?.composition;if(!ue(s))return;let i=I(s);this.session.subscribedCompositionKeys.has(i)&&(this.eventDispatcher.push(e),e.type==="site-edit.graph.invalidated"&&i===he(this.session)&&(this.session.activeComposition=void 0,this.session.subscribedCompositionKeys.delete(i)))}sendResult(e,s,i){this.sendJson({type:"response",payload:{id:e,kind:s,result:i}})}async handleRawMessage(e){try{await this.handleMessage(l.parseMessage(e,{validateOperationRequest:this.options.validateOperationRequest}))}catch(s){let i=le(e);this.sendJson({type:"error",payload:{...i,message:T(s),code:_(s)}})}}sendJson(e){this.options.socket.send(l.stringifyMessage(e))}async handleBufferedOperation(e,s,i){this.eventDispatcher.beginBuffering();try{let o=await i();this.sendResult(e,s,o)}catch(o){this.sendJson({type:"error",payload:{id:e,kind:s,message:T(o),code:_(o)}})}finally{this.eventDispatcher.flush()}}},S=class extends Error{constructor(e,s){super(s),this.code=e,this.name="BridgeProtocolError"}},O=class{constructor(e){this.send=e,this.bufferedEvents=null}push(e){let s={type:"event",payload:{event:e}};if(this.bufferedEvents){this.bufferedEvents.push(s);return}this.send(s)}beginBuffering(){this.bufferedEvents=[]}flush(){let e=this.bufferedEvents??[];this.bufferedEvents=null,e.forEach(s=>this.send(s))}},D=class{constructor(e=64){this.maxQueued=e,this.queue=Promise.resolve(),this.queued=0}enqueue(e){if(this.queued>=this.maxQueued)throw new Error("Bridge request queue is full");this.queued+=1;let s=async()=>{this.queued-=1,await e()},i=this.queue.then(s,s);return this.queue=i.then(()=>{},()=>{}),i}};function ae(t,e){if(!d(t)||typeof t.id!="string"||!l.isRequestKind(t.kind))return!1;let s=x(t.composition);switch(t.kind){case"initialize-session":return s&&(t.mutationContext===void 0||k(t.mutationContext));case"get-document":case"get-style-context":return s;case"get-object-edit-context":case"get-class-name-source":case"resolve-source-location":return typeof t.key=="string"&&s;case"get-history-status":return s;case"get-source-tree":return s;case"get-source-file":return typeof t.path=="string"&&s;case"execute":return s&&ce(t.request)&&(t.request.mutationContext===void 0||k(t.request.mutationContext))&&(e.validateOperationRequest?.(t.request)??!0);case"undo":case"redo":return s&&t.mutationContext===void 0||s&&k(t.mutationContext)}}function ce(t){return d(t)&&typeof t.id=="string"&&typeof t.siteId=="string"&&typeof t.baseSnapshotId=="string"&&x(t.composition)&&typeof t.kind=="string"&&d(t.target)&&(t.target.kind!=="route"||x(t.target.composition))&&typeof t.documentVersion=="number"&&Number.isInteger(t.documentVersion)&&t.documentVersion>=0&&d(t.params)}function x(t){return d(t)&&typeof t.routeId=="string"&&t.routeId.length>0&&(t.templateId===void 0||typeof t.templateId=="string"&&t.templateId.length>0)&&Object.keys(t).every(e=>e==="routeId"||e==="templateId")}function ue(t){return d(t)&&typeof t.routeId=="string"&&(t.effectiveTemplateId===void 0||typeof t.effectiveTemplateId=="string")}function v(t){if(x(t.composition))return t.composition;throw new S(M,"A composition selector is required for this request.")}function de(t){if(d(t)&&x(t.composition))return t.composition;throw new S(M,"A composition selector is required for execute.")}function j(t){return{routeId:t.routeId,...t.effectiveTemplateId?{templateId:t.effectiveTemplateId}:{}}}function he(t){return t.activeComposition?I(t.activeComposition):null}function I(t){return JSON.stringify([t.routeId,t.effectiveTemplateId??null])}function f(t,e){return d(t)&&t.ok===!0?{...t,composition:e}:t}function pe(t,e){return!d(t)||t.ok!==!0?t:{...t,...e?{composition:e}:{},data:z(t.data)}}function z(t){let e=t;return U(e.routeId?e:{...e,routeId:e.composition.routeId})}function d(t){return typeof t=="object"&&t!==null}function k(t){return d(t)&&typeof t.editingSessionId=="string"&&t.editingSessionId.length>0&&typeof t.lockId=="string"&&t.lockId.length>0&&typeof t.ownerId=="string"&&t.ownerId.length>0&&typeof t.leaseAssertion=="string"&&t.leaseAssertion.length>0}function _(t){if(!(!d(t)||typeof t.code!="string"||t.code.length===0))return t.code}function T(t){return t instanceof Error||d(t)&&typeof t.message=="string"&&t.message.length>0?t.message:"Unknown websocket operation failure"}function le(t){try{return l.extractRequestInfo(JSON.parse(t))}catch{return{id:"unknown",kind:"get-document"}}}var E=class{constructor(){this.tail=Promise.resolve()}run(e){let s=this.tail.then(e,e);return this.tail=s.then(()=>{},()=>{}),s}};import{SiteEditOperationRequestSchema as be,computeSiteEditCompositionKey as w}from"@vcp-dev/contracts";var ve="127.0.0.1",ke=30218,_e="/__vcp/site-edit/bridge",X=6*1024*1024,Te=X*2,Oe=3e3,L=50,$="__VCP_SITE_EDIT_BRIDGE_SERVERS__";function nt(t){let e=ee(t),s=se(e),i=te(),o=i.get(s);if(o)return o;let n=new b(e);i.set(s,n);try{n.start()}catch(r){throw i.delete(s),n.stop(),r}return n}function ot(t,e,s={}){let i=new b(ee(e),t,!1,s);return i.start({listen:!1}),i}var b=class{constructor(e,s=me.createServer((n,r)=>{r.writeHead(404),r.end("VCP site edit bridge server")}),i=!0,o={}){this.options=e,this.server=s,this.closeHttpServerOnStop=i,this.dependencies=o,this.runtime=null,this.activeHistorySessionId=null,this.historySessionTransition=Promise.resolve(),this.mutationQueue=new E,this.eventListeners=new Set,this.routes=[],this.compositions=[],this.compositionFiles=[],this.compositionResolutionError=null,this.stopWatching=null,this.stopWebSocketServer=null,this.pendingChangedFiles=new Set,this.fileChangeTimer=null,this.isStarted=!1,this.runtimeVersionFloors=new Map,this.activeHistoryStore=null,this.versionPersistence=Promise.resolve()}start(e={}){if(this.isStarted)return;this.refreshCompositions(!0),this.isStarted=!0,this.createRuntime();let s=Be({server:this.server,path:this.options.path,sessionKey:this.options.sessionKey,host:this.options.host,allowedOrigins:this.options.allowedOrigins,engine:this.createBridgeEngine()});this.stopWebSocketServer=s.stop,this.stopWatching=new Ee({projectRoot:this.options.projectRoot,watch_dirs:De(this.options.runtime.watch_dirs),interval_ms:this.options.runtime.watch_interval_ms,debounce_ms:this.options.runtime.watch_debounce_ms??L,max_dirs:this.options.runtime.watch_max_dirs,max_files:this.options.runtime.watch_max_files,max_depth:this.options.runtime.watch_max_depth,max_startup_ms:this.options.runtime.watch_max_startup_ms,on_change:i=>this.handleFileChanged(i),on_batch_change:i=>this.handleFilesChanged(i)}).start(),e.listen!==!1&&this.server.listen(this.options.port,this.options.host)}getHealth(){let e=!!this.runtime&&!this.compositionResolutionError;return{ok:this.isStarted&&e,bridgePath:this.options.path,runtimeReady:e,routesIndexed:this.routes.length,sessionRequired:!!this.options.sessionKey}}stop(){this.stopWatching?.(),this.stopWatching=null,this.flushChangedFiles(),this.fileChangeTimer&&(clearTimeout(this.fileChangeTimer),this.fileChangeTimer=null),this.stopWebSocketServer?.(),this.stopWebSocketServer=null,this.runtime?.dispose(),this.runtime=null,this.compositions=[],this.compositionFiles=[],this.compositionResolutionError=null,this.closeHttpServerOnStop&&this.server.close();let e=te(),s=se(this.options);e.get(s)===this&&e.delete(s),this.isStarted=!1}createRuntime(e,s=null){let i=this.runtime;this.activeHistoryStore=e??null;let o=(this.dependencies.createRuntime??Ie)({...this.options.tenantId?{tenantId:this.options.tenantId}:{},siteId:this.options.siteId,snapshotId:this.options.snapshotId,projectRoot:this.options.projectRoot,compositions:this.compositions,onEvent:n=>{"version"in n&&typeof n.version=="number"&&this.recordRuntimeVersion(n.version,"composition"in n?n.composition:void 0);for(let r of this.eventListeners)r(n)},...e?{historyStore:e}:{},...this.getInitialDocumentVersions().length>0?{initialDocumentVersions:this.getInitialDocumentVersions()}:{}});this.runtime=o,this.activeHistorySessionId=s,i?.dispose()}createBridgeEngine(){return{resolveComposition:e=>this.resolveComposition(e),initializeSession:e=>this.mutationQueue.run(async()=>{let s=await this.bindHistorySession(this.options.snapshotId);if(!s.ok)throw new Error(`${s.code}: ${s.message}`);let i=Ae(e.composition),o=this.getRuntime(),n=m(i);await o.initializeComposition(n);let a=o.getDocument(n).data;await this.recordRuntimeVersion(a.version,i);let c=(await o.getHistoryStatus()).data;return{ok:!0,composition:i,data:{document:a,historyStatus:c}}}),getDocument:async e=>{let s=this.getRuntime(),i=m(e);await s.initializeComposition(i);let o=s.getDocument(i);return await this.recordRuntimeVersion(o.data.version,e),{...o,composition:e}},getHistoryStatus:async e=>({...await this.getRuntime().getHistoryStatus(),composition:e}),getStyleContext:async e=>this.getRuntime().getStyleContext(m(e)),getObjectEditContext:async(e,s)=>this.getRuntime().getObjectEditContext(e,m(s)),getClassNameSource:async(e,s)=>this.getRuntime().getClassNameSource(e,m(s)),getSourceTree:async e=>this.getRuntime().getSourceTree(m(e)),getSourceFile:async e=>this.getRuntime().getSourceFile({path:e.path,composition:m(e.composition)}),resolveSourceLocation:async e=>this.getRuntime().resolveSourceLocation({key:e.key,composition:m(e.composition)}),execute:(e,s)=>this.mutationQueue.run(async()=>{let i=await this.bindHistorySession(this.options.snapshotId);if(!i.ok)return F(i,e);let o=await this.getRuntime().executeOperation(e);return o.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(o.data.resultVersion,o.composition),o}),undo:e=>this.mutationQueue.run(async()=>{let s=await this.bindHistorySession(this.options.snapshotId);if(!s.ok)return F(s,void 0,e);let i=await this.getRuntime().undo();return i.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(i.data.resultVersion,i.composition??e),i.composition?i:{...i,composition:e}}),redo:e=>this.mutationQueue.run(async()=>{let s=await this.bindHistorySession(this.options.snapshotId);if(!s.ok)return F(s,void 0,e);let i=await this.getRuntime().redo();return i.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(i.data.resultVersion,i.composition??e),i.composition?i:{...i,composition:e}}),subscribe:e=>(this.eventListeners.add(e),()=>this.eventListeners.delete(e))}}async bindHistorySession(e){if(!this.options.historyRoot)return{ok:!1,code:"RECOVERY_PERSIST_FAILED",message:"Durable edit history is not configured."};if(this.activeHistorySessionId===e)return{ok:!0};let s=this.historySessionTransition.then(async()=>{if(this.activeHistorySessionId===e)return;let i=await(this.dependencies.openHistoryStore??Se)(Fe({root:this.options.historyRoot,siteId:this.options.siteId,snapshotId:this.options.snapshotId,editingSessionId:e}));if(!this.isStarted)return;let o=i.readDocumentVersion?await i.readDocumentVersion():0,n=this.compositions[0]?.context;if(n){let r=w(n);this.runtimeVersionFloors.set(r,Math.max(this.runtimeVersionFloors.get(r)??0,o))}this.createRuntime(i,e)});this.historySessionTransition=s.catch(()=>{});try{return await s,{ok:!0}}catch{return{ok:!1,code:"RECOVERY_PERSIST_FAILED",message:"Durable edit history could not be opened."}}}recordRuntimeVersion(e,s){let i=s?w(s):null;i&&this.runtimeVersionFloors.set(i,Math.max(this.runtimeVersionFloors.get(i)??0,e));let o=this.activeHistoryStore;if(!o?.writeDocumentVersion)return Promise.resolve();let n=i?this.runtimeVersionFloors.get(i)??e:e;return this.versionPersistence=this.versionPersistence.then(()=>o.writeDocumentVersion(n)).catch(()=>{}),this.versionPersistence}handleFileChanged(e){this.handleFilesChanged([e])}handleFilesChanged(e){for(let i of e)this.pendingChangedFiles.add(i);this.fileChangeTimer&&clearTimeout(this.fileChangeTimer);let s=this.options.runtime.watch_debounce_ms??L;this.fileChangeTimer=setTimeout(()=>{this.fileChangeTimer=null,this.flushChangedFiles()},s),this.fileChangeTimer?.unref?.()}flushChangedFiles(){if(this.fileChangeTimer&&(clearTimeout(this.fileChangeTimer),this.fileChangeTimer=null),this.pendingChangedFiles.size===0)return;let e=[...this.pendingChangedFiles].sort((s,i)=>s.localeCompare(i));if(this.pendingChangedFiles.clear(),!!this.refreshCompositions(!1))for(let s of e)this.runtime?.notifyFileChanged(s)}refreshCompositions(e=!1){try{let s=Me(this.options.projectRoot),i=Re(s),o=i.length>0?i:(this.options.runtime.routes??[]).map(c=>({...c})),n=Ce({files:s});if(n.length===0)throw new Error("No canonical App Router composition is indexed by the preview bridge.");let r=new Map(this.compositions.map(c=>[w(c.context),c])),a=new Map(n.map(c=>[w(c.context),c]));if(this.runtime){for(let[c,p]of r){let y=a.get(c);(!y||y.entryFile!==p.entryFile)&&this.runtime.unregisterComposition(m(p.context))}for(let[c,p]of a){let y=r.get(c);(!y||y.entryFile!==p.entryFile)&&this.runtime.registerComposition(p.context,p.entryFile)}}return this.routes=o,this.compositions=n,this.compositionFiles=s,this.compositionResolutionError=null,!0}catch(s){let i=s instanceof Error?s:new Error(String(s));if(this.compositionResolutionError=i,e)throw i;return!1}}resolveComposition(e){if(this.compositionResolutionError)throw this.compositionResolutionError;let s=xe(e.routeId,this.routes,this.options.basePath);if(!s)throw new Error(`Route is not indexed by the preview bridge: ${e.routeId}`);let i=this.routes.find(r=>r.routeId===s);if(!i)throw new Error(`Route is not indexed by the preview bridge: ${e.routeId}`);let o=we({selector:{routeId:s,...e.templateId?{templateId:e.templateId}:{}},files:this.compositionFiles,canonicalEntryFile:i.entryFile}),n=w(o.context);if(!this.compositions.some(r=>w(r.context)===n))throw new Error(`Composition is not registered by the preview bridge: ${n}`);return o}getInitialDocumentVersions(){return this.compositions.flatMap(e=>{let s=this.runtimeVersionFloors.get(w(e.context));return s===void 0?[]:[{composition:e.context,version:s}]})}getRuntime(){if(!this.runtime)throw new Error("VCP site edit preview bridge runtime is not ready");return this.runtime}};function ee(t){return{tenantId:t.tenantId,siteId:t.siteId,snapshotId:t.snapshotId,projectRoot:g.resolve(t.projectRoot??process.cwd()),basePath:t.basePath??"",host:t.host??ve,port:t.port??ke,path:t.path??_e,sessionKey:t.sessionKey??Ue(),historyRoot:t.historyRoot,allowedOrigins:t.allowedOrigins??[],runtime:t.runtime??{}}}function De(t){let e=["app","src/app","components/site","src/components/site","lib/generated","src/lib/generated","public"];return[...new Set([...t?.length?t:e,".vcp"])]}function Me(t){let e=[],s=["app","src/app",".vcp"],i=new Set([".git",".next",".turbo","coverage","dist","node_modules","output","snapshot-store"]),o=n=>{if(!A.existsSync(n))return;let r;try{r=A.readdirSync(n,{withFileTypes:!0})}catch{return}for(let a of r){if(a.name.startsWith(".")&&a.name!==".vcp")continue;if(a.isDirectory()){if(i.has(a.name))continue;o(g.join(n,a.name));continue}if(!a.isFile())continue;let c=g.join(n,a.name),p="";try{p=A.readFileSync(c,"utf8")}catch{}e.push({path:g.relative(t,c).replaceAll(g.sep,"/"),content:p})}};for(let n of s)o(g.join(t,n));return e.sort((n,r)=>n.path.localeCompare(r.path))}function Ae(t){if(!t||typeof t!="object"||typeof t.routeId!="string")throw new Error("Normalized composition context is required.");if("effectiveTemplateId"in t)return t;let e=t;return{routeId:e.routeId,...e.templateId?{effectiveTemplateId:e.templateId}:{}}}function m(t){return{routeId:t.routeId,...t.effectiveTemplateId?{templateId:t.effectiveTemplateId}:{}}}function Fe(t){return g.join(g.resolve(t.root),J(t.siteId),J(t.snapshotId),Y("sha256").update(t.editingSessionId).digest("hex").slice(0,32))}function J(t){return/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(t)&&t!=="."&&t!==".."?t:Y("sha256").update(t).digest("hex").slice(0,32)}function te(){let t=globalThis;return t[$]??=new Map,t[$]}function se(t){return`${t.projectRoot}:${t.host}:${t.port}:${t.path}:${t.historyRoot??""}`}function F(t,e,s){let i=s??(e?.composition?{routeId:e.composition.routeId,...e.composition.templateId?{effectiveTemplateId:e.composition.templateId}:{}}:void 0);if(!i)throw new Error("A normalized composition is required to construct a mutation result.");return{ok:!1,composition:i,error:{code:t.code,message:t.message},data:{requestId:e?.id??"mutation-context",kind:e?.kind??"update-text",composition:i,target:e?.target??{kind:"node",key:""},resultVersion:e?.documentVersion??0}}}function Be(t){let e=new ye({maxPayload:X,noServer:!0}),s=new WeakSet,i=n=>{new R({socket:new K(n),engine:t.engine,validateOperationRequest:r=>be.safeParse(r).success})},o=(n,r,a)=>{if(!Ke(n,t))return;let c=qe(n,t);if(!c){r.write(`HTTP/1.1 401 Unauthorized\r
2
2
  Connection: close\r
3
3
  \r
4
- `),r.destroy();return}h.authenticatedByHeader&&s.add(o),e.handleUpgrade(o,r,p,y=>{e.emit("connection",y,o)})};return t.server.on("upgrade",i),e.on("connection",(o,r)=>{if(s.has(r)){n(o);return}ye(o,t.sessionKey,()=>{n(o)})}),e.stop=()=>{t.server.off("upgrade",i);for(let o of e.clients)o.close(1001,"bridge stopped");e.close()},e}var b=class{constructor(e){this.socket=e,this.onmessage=null,this.onclose=null,e.on("error",()=>{}),e.on("message",s=>{this.onmessage?.({data:s.toString()})}),e.on("close",()=>{this.onclose?.()})}send(e){if(this.socket.readyState===U.OPEN){if(this.socket.bufferedAmount+Buffer.byteLength(e,"utf8")>he){this.socket.close(1013,"bridge backpressure");return}this.socket.send(e)}}close(e,s){this.socket.close(e,s)}};function fe(t,e){return new URL(t.url??"/","http://localhost").pathname===e.path}function me(t,e){if(new URL(t.url??"/","http://localhost").searchParams.has("vcp_bridge_key"))return null;let n=x(t.headers["x-vcp-site-edit-key"]),i=L(n,e.sessionKey),o=x(t.headers.host),r=x(t.headers.origin);return o&&!Ie(o,e.host,r)?null:r?Se(r,o,e.allowedOrigins)?{authenticatedByHeader:i}:null:i?{authenticatedByHeader:!0}:null}function ye(t,e,s){let n=setTimeout(()=>{t.close(1008,"bridge authentication timeout")},pe),i,o=()=>{clearTimeout(n),t.off("message",i),t.off("close",o)},r=()=>{o(),t.close(1008,"bridge authentication failed")};i=p=>{try{let h=d.parseMessage(p.toString());if(h.type!=="auth"||!L(h.payload.key,e)){r();return}o(),t.readyState===U.OPEN&&t.send(d.stringifyMessage({type:"auth-ok",payload:{ok:!0}})),s()}catch{r()}},t.on("message",i),t.on("close",o)}function L(t,e){if(!t)return!1;let s=Buffer.from(t),n=Buffer.from(e);return s.length===n.length&&ee(s,n)}function Ie(t,e,s){let n=K(t),i=K(e);return n===i||A(i)&&A(n)&&(!s||v(s,t))||Re(i)&&(!s||v(s,t))}function Re(t){return t==="0.0.0.0"||t==="::"}function A(t){return t==="localhost"||t==="127.0.0.1"||t==="::1"}function Se(t,e,s){return s.includes(t)||(e?v(t,e):!1)}function v(t,e){try{return new URL(t).host===N(e)}catch{return!1}}function K(t){let e=N(t);return e.startsWith("[")?e.slice(1,e.indexOf("]")):e.split(":").length-1===1?e.split(":",1)[0]??"":e}function N(t){return t.trim().toLowerCase()}function x(t){return Array.isArray(t)?t[0]:t}function we(){return Z(32).toString("base64url")}export{he as SITE_EDIT_BRIDGE_MAX_BUFFERED_BYTES,P as SITE_EDIT_BRIDGE_MAX_PAYLOAD_BYTES,m as SiteEditBridgeServer,Ke as attachSiteEditBridgeServer,ge as attachSiteEditWebSocketServer,Ae as ensureSiteEditBridgeServerStarted};
4
+ `),r.destroy();return}c.authenticatedByHeader&&s.add(n),e.handleUpgrade(n,r,a,p=>{e.emit("connection",p,n)})};return t.server.on("upgrade",o),e.on("connection",(n,r)=>{if(s.has(r)){i(n);return}He(n,t.sessionKey,()=>{i(n)})}),e.stop=()=>{t.server.off("upgrade",o);for(let n of e.clients)n.close(1001,"bridge stopped");e.close()},e}var K=class{constructor(e){this.socket=e,this.onmessage=null,this.onclose=null,e.on("error",()=>{}),e.on("message",s=>{this.onmessage?.({data:s.toString()})}),e.on("close",()=>{this.onclose?.()})}send(e){if(this.socket.readyState===Z.OPEN){if(this.socket.bufferedAmount+Buffer.byteLength(e,"utf8")>Te){this.socket.close(1013,"bridge backpressure");return}this.socket.send(e)}}close(e,s){this.socket.close(e,s)}};function Ke(t,e){return new URL(t.url??"/","http://localhost").pathname===e.path}function qe(t,e){if(new URL(t.url??"/","http://localhost").searchParams.has("vcp_bridge_key"))return null;let i=B(t.headers["x-vcp-site-edit-key"]),o=ie(i,e.sessionKey),n=B(t.headers.host),r=B(t.headers.origin);return n&&!Ve(n,e.host,r)?null:r?Ne(r,n,e.allowedOrigins)?{authenticatedByHeader:o}:null:o?{authenticatedByHeader:!0}:null}function He(t,e,s){let i=setTimeout(()=>{t.close(1008,"bridge authentication timeout")},Oe),o,n=()=>{clearTimeout(i),t.off("message",o),t.off("close",n)},r=()=>{n(),t.close(1008,"bridge authentication failed")};o=a=>{try{let c=l.parseMessage(a.toString());if(c.type!=="auth"||!ie(c.payload.key,e)){r();return}n(),t.readyState===Z.OPEN&&t.send(l.stringifyMessage({type:"auth-ok",payload:{ok:!0}})),s()}catch{r()}},t.on("message",o),t.on("close",n)}function ie(t,e){if(!t)return!1;let s=Buffer.from(t),i=Buffer.from(e);return s.length===i.length&&ge(s,i)}function Ve(t,e,s){let i=G(t),o=G(e);return i===o||Q(o)&&Q(i)&&(!s||q(s,t))||Pe(o)&&(!s||q(s,t))}function Pe(t){return t==="0.0.0.0"||t==="::"}function Q(t){return t==="localhost"||t==="127.0.0.1"||t==="::1"}function Ne(t,e,s){return s.includes(t)||(e?q(t,e):!1)}function q(t,e){try{return new URL(t).host===ne(e)}catch{return!1}}function G(t){let e=ne(t);return e.startsWith("[")?e.slice(1,e.indexOf("]")):e.split(":").length-1===1?e.split(":",1)[0]??"":e}function ne(t){return t.trim().toLowerCase()}function B(t){return Array.isArray(t)?t[0]:t}function Ue(){return fe(32).toString("base64url")}export{Te as SITE_EDIT_BRIDGE_MAX_BUFFERED_BYTES,X as SITE_EDIT_BRIDGE_MAX_PAYLOAD_BYTES,b as SiteEditBridgeServer,ot as attachSiteEditBridgeServer,Be as attachSiteEditWebSocketServer,nt as ensureSiteEditBridgeServerStarted};
@@ -1,4 +1,4 @@
1
- import type { SiteEditCommandSuccess, SiteEditClassNameSourceStyleContext, SiteEditEvent, SiteEditObjectEditContext, SiteEditGetClassNameSourceCommandResult, SiteEditOperationCommandResult, SiteEditOperationRequest, SiteEditRenderDocument, SiteEditSourceFileResponse, SiteEditSourceLocation, SiteEditSourceTreeResponse } from "@vcp-dev/contracts";
1
+ import type { SiteEditCommandSuccess, SiteEditClassNameSourceStyleContext, SiteEditCompositionContext, SiteEditCompositionSelector, SiteEditEvent, SiteEditObjectEditContext, SiteEditGetClassNameSourceCommandResult, SiteEditOperationCommandResult, SiteEditOperationRequest, SiteEditRenderDocument, SiteEditSourceFileResponse, SiteEditSourceLocation, SiteEditSourceTreeResponse } from "@vcp-dev/contracts";
2
2
  import type { SiteEditHistoryStatus } from "./protocol.js";
3
3
  export declare const VCP_WINDOW_MESSAGE_SOURCE = "vcp-window-message";
4
4
  export declare const VCP_WINDOW_MESSAGE_VERSION = 1;
@@ -62,6 +62,7 @@ export type SiteEditFrameRuntimeResizeSession = {
62
62
  startHeight: number;
63
63
  width: number;
64
64
  height: number;
65
+ baselineStyleDeclarations?: SiteEditFrameRuntimeStyleDeclaration[];
65
66
  };
66
67
  export type SiteEditFrameRuntimeNodePatch = {
67
68
  attributes?: Record<string, string | null>;
@@ -114,7 +115,8 @@ export type SiteEditFrameRuntimeDropTarget = {
114
115
  export type SiteEditFrameRuntimeBridgeStatusCode = "connecting" | "ready" | "reconnecting" | "failed" | "reload-required";
115
116
  export type SiteEditFrameRuntimeBridgeStatus = {
116
117
  state: SiteEditFrameRuntimeBridgeStatusCode;
117
- routeId?: string;
118
+ composition: SiteEditCompositionContext;
119
+ sequence: number;
118
120
  attempt?: number;
119
121
  retryInMs?: number;
120
122
  messageKey?: string;
@@ -132,13 +134,16 @@ export type SiteEditFrameRuntimeRequestBody = {
132
134
  type: "request";
133
135
  id: string;
134
136
  kind: "bridge-get-source-tree";
135
- payload: Record<string, never>;
137
+ payload: {
138
+ composition: SiteEditCompositionSelector;
139
+ };
136
140
  } | {
137
141
  type: "request";
138
142
  id: string;
139
143
  kind: "bridge-get-source-file";
140
144
  payload: {
141
145
  path: string;
146
+ composition: SiteEditCompositionSelector;
142
147
  };
143
148
  } | {
144
149
  type: "request";
@@ -146,7 +151,7 @@ export type SiteEditFrameRuntimeRequestBody = {
146
151
  kind: "bridge-resolve-source-location";
147
152
  payload: {
148
153
  key: string;
149
- routeId?: string;
154
+ composition: SiteEditCompositionSelector;
150
155
  };
151
156
  } | {
152
157
  type: "request";
@@ -270,14 +275,14 @@ export type SiteEditFrameRuntimeRequestBody = {
270
275
  id: string;
271
276
  kind: "bridge-initialize-session";
272
277
  payload: {
273
- routeId: string;
278
+ composition: SiteEditCompositionSelector;
274
279
  };
275
280
  } | {
276
281
  type: "request";
277
282
  id: string;
278
283
  kind: "bridge-get-document" | "bridge-ensure-document-version" | "bridge-acknowledge-document-version";
279
284
  payload: {
280
- routeId: string;
285
+ composition: SiteEditCompositionSelector;
281
286
  minVersion?: number;
282
287
  version?: number;
283
288
  };
@@ -285,13 +290,15 @@ export type SiteEditFrameRuntimeRequestBody = {
285
290
  type: "request";
286
291
  id: string;
287
292
  kind: "bridge-get-history-status";
288
- payload: Record<string, never>;
293
+ payload: {
294
+ composition: SiteEditCompositionSelector;
295
+ };
289
296
  } | {
290
297
  type: "request";
291
298
  id: string;
292
299
  kind: "bridge-get-style-context";
293
300
  payload: {
294
- routeId: string;
301
+ composition: SiteEditCompositionSelector;
295
302
  };
296
303
  } | {
297
304
  type: "request";
@@ -299,26 +306,30 @@ export type SiteEditFrameRuntimeRequestBody = {
299
306
  kind: "bridge-get-object-edit-context" | "bridge-get-class-name-source";
300
307
  payload: {
301
308
  key: string;
302
- routeId?: string;
309
+ composition: SiteEditCompositionSelector;
303
310
  };
304
311
  } | {
305
312
  type: "request";
306
313
  id: string;
307
314
  kind: "bridge-execute";
308
315
  payload: {
316
+ composition: SiteEditCompositionSelector;
309
317
  request: SiteEditOperationRequest;
310
318
  };
311
319
  } | {
312
320
  type: "request";
313
321
  id: string;
314
322
  kind: "bridge-undo" | "bridge-redo";
315
- payload: Record<string, never>;
323
+ payload: {
324
+ composition: SiteEditCompositionSelector;
325
+ };
316
326
  } | {
317
327
  type: "request";
318
328
  id: string;
319
329
  kind: "bridge-subscribe" | "bridge-unsubscribe";
320
330
  payload: {
321
331
  subscriptionId: string;
332
+ composition: SiteEditCompositionSelector;
322
333
  };
323
334
  };
324
335
  export type SiteEditFrameRuntimeMargin = {
@@ -501,6 +512,7 @@ export type SiteEditFrameRuntimeEventBody = {
501
512
  kind: "bridge-event";
502
513
  payload: {
503
514
  subscriptionId: string;
515
+ composition: SiteEditCompositionContext;
504
516
  event: SiteEditEvent;
505
517
  };
506
518
  } | {
@@ -522,8 +534,10 @@ export type SiteEditFrameRuntimeEventBody = {
522
534
  type: "event";
523
535
  kind: "route-ready";
524
536
  payload: {
525
- routeId: string;
526
- version?: number;
537
+ composition: SiteEditCompositionContext;
538
+ editEngineVersion: string;
539
+ sequence: number;
540
+ version: number;
527
541
  };
528
542
  } | {
529
543
  type: "event";
@@ -1 +1 @@
1
- var _="vcp-window-message",ce=1;function M(e){return{source:_,version:1,namespace:e.namespace,channel:e.channel,...e.sessionKey?{sessionKey:e.sessionKey}:{},body:e.body}}function W(e){try{return i(e)?d(e,"source",_)&&d(e,"version",1)&&s(e,"namespace")&&s(e,"channel")&&u(e,"body")&&(!l(e,"sessionKey")||s(e,"sessionKey")):!1}catch{return!1}}var O="site-edit",N="frame-runtime",C=1,R=1,w=1,ae=24;function de(e,r={}){return M({namespace:O,channel:N,sessionKey:r.sessionKey,body:e})}function ue(e){try{return!W(e)||e.namespace!==O||e.channel!==N?!1:oe(e.body)}catch{return!1}}var l=(e,r)=>Object.prototype.hasOwnProperty.call(e,r);function u(e,r){let t=Object.getOwnPropertyDescriptor(e,r);return t!==void 0&&"value"in t}function n(e,r){return Object.getOwnPropertyDescriptor(e,r)?.value}function d(e,r,t){return u(e,r)&&n(e,r)===t}function s(e,r){return u(e,r)&&typeof n(e,r)=="string"}function S(e,r){return u(e,r)&&typeof n(e,r)=="boolean"}function o(e,r){let t=n(e,r);return u(e,r)&&typeof t=="number"&&Number.isFinite(t)}function K(e,r){let t=n(e,r);return u(e,r)&&typeof t=="number"&&Number.isInteger(t)&&t>0}function g(e,r){return!l(e,r)||n(e,r)===void 0||s(e,r)}function y(e,r){return!l(e,r)||n(e,r)===void 0||o(e,r)}function b(e,r){let t=n(e,r);return!l(e,r)||t===void 0||u(e,r)&&typeof t=="number"&&Number.isInteger(t)&&t>=0}function a(e,r){return!l(e,r)||n(e,r)===void 0}function i(e){if(typeof e!="object"||e===null||Array.isArray(e))return!1;let r=Object.getPrototypeOf(e);return r===Object.prototype||r===null}function G(e){return i(e)&&Reflect.ownKeys(e).length===0}function A(e){if(!Array.isArray(e))return!1;for(let r=0;r<e.length;r+=1){let t=Object.getOwnPropertyDescriptor(e,String(r));if(t===void 0||!("value"in t)||typeof t.value!="string")return!1}return!0}function p(e){return i(e)&&s(e,"key")&&b(e,"instanceIndex")&&b(e,"instanceCount")&&b(e,"textSegmentIndex")}function B(e){return i(e)&&s(e,"blockId")&&p(n(e,"ref"))&&h(n(e,"rect"))&&S(e,"targetIsSectionRoot")}function L(e){if(!i(e))return!1;let r=n(e,"placement"),t=n(e,"boundary");return s(e,"anchorBlockId")&&p(n(e,"anchorRef"))&&(r==="before"||r==="after")&&i(t)&&o(t,"top")&&o(t,"left")&&o(t,"width")}function h(e){return i(e)&&["top","left","width","height"].every(r=>o(e,r))}function x(e){if(!i(e))return!1;let r=n(e,"rect"),t=n(e,"layout"),c=i(t)?n(t,"containingBlock"):null,f=n(e,"scrollContext"),E=i(c)&&(d(c,"kind","viewport")&&Reflect.ownKeys(c).length===1||d(c,"kind","document")&&Reflect.ownKeys(c).length===1||d(c,"kind","element")&&s(c,"runtimeNodeId"));return d(e,"version",C)&&s(e,"runtimeNodeId")&&i(r)&&h(n(r,"viewport"))&&h(n(r,"document"))&&i(t)&&s(t,"position")&&s(t,"transform")&&E&&i(f)&&["scrollX","scrollY","viewportWidth","viewportHeight"].every(m=>o(f,m))&&u(f,"scrollContainers")&&z(n(f,"scrollContainers"))}function z(e){return Array.isArray(e)&&e.every(r=>i(r)&&s(r,"runtimeNodeId")&&o(r,"scrollLeft")&&o(r,"scrollTop"))}function I(e){return i(e)&&(a(e,"layoutSnapshot")||x(n(e,"layoutSnapshot")))}function U(e){return i(e)&&p(n(e,"ref"))&&u(e,"layoutSnapshot")&&x(n(e,"layoutSnapshot"))&&(a(e,"childBoxes")||H(n(e,"childBoxes")))&&(a(e,"childRects")||q(n(e,"childRects")))&&(a(e,"layout")||j(n(e,"layout")))&&(a(e,"spacing")||X(n(e,"spacing")))}function j(e){if(!i(e))return!1;let r=n(e,"indicatorOrientation");return s(e,"display")&&(r==="horizontal"||r==="vertical")&&g(e,"flexDirection")&&g(e,"gridAutoFlow")}function q(e){return Array.isArray(e)&&e.every(r=>h(r))}function H(e){return Array.isArray(e)&&e.every(r=>i(r)&&h(n(r,"rect"))&&T(n(r,"margin")))}function T(e){return i(e)&&["marginTop","marginRight","marginBottom","marginLeft"].every(r=>o(e,r))}function X(e){return T(e)&&["paddingTop","paddingRight","paddingBottom","paddingLeft","borderTopWidth","borderRightWidth","borderBottomWidth","borderLeftWidth","columnGap","rowGap"].every(r=>o(e,r))}function Y(e){if(!Array.isArray(e))return!1;for(let r=0;r<e.length;r+=1){let t=Object.getOwnPropertyDescriptor(e,String(r));if(t===void 0||!("value"in t)||!U(t.value))return!1}return!0}function Z(e){return i(e)&&Reflect.ownKeys(e).every(r=>typeof r=="string"&&u(e,r)&&(typeof n(e,r)=="string"||n(e,r)===null))}function V(e){return e==null||typeof e=="string"||typeof e=="number"&&Number.isFinite(e)}function k(e){return i(e)&&Reflect.ownKeys(e).every(r=>typeof r=="string"&&u(e,r)&&V(n(e,r)))}function J(e){if(!i(e))return!1;let r=n(e,"priority");return s(e,"property")&&u(e,"value")&&V(n(e,"value"))&&(!l(e,"priority")||r===void 0||r==="important")}function Q(e){return i(e)?(a(e,"attributes")||Z(n(e,"attributes")))&&g(e,"className")&&(a(e,"style")||k(n(e,"style")))&&(a(e,"styleDeclarations")||Array.isArray(n(e,"styleDeclarations"))&&n(e,"styleDeclarations").every(J)):!1}function $(e){return i(e)&&o(e,"x")&&o(e,"y")&&(a(e,"detailLevel")||d(e,"detailLevel","summary")||d(e,"detailLevel","full"))}function v(e){return i(e)&&p(n(e,"ref"))}function ee(e){if(!i(e)||!i(n(e,"variables")))return!1;let r=n(e,"variables");return Reflect.ownKeys(r).every(t=>typeof t=="string"&&s(r,t))?a(e,"stylesheets")||A(n(e,"stylesheets")):!1}function te(e){if(!d(e,"type","request")||!s(e,"id")||!s(e,"kind")||!u(e,"payload"))return!1;let r=n(e,"kind"),t=n(e,"payload");switch(r){case"hit-test-at-point":case"start-text-edit-at-point":return $(t);case"bridge-get-source-tree":case"get-scroll-metrics":case"clear-theme-override":case"bridge-get-history-status":case"bridge-undo":case"bridge-redo":return G(t);case"bridge-get-source-file":return i(t)&&s(t,"path");case"bridge-resolve-source-location":case"bridge-get-object-edit-context":case"bridge-get-class-name-source":return i(t)&&s(t,"key")&&g(t,"routeId");case"scroll-to":return i(t)&&o(t,"x")&&o(t,"y");case"scroll-by":return i(t)&&o(t,"deltaX")&&o(t,"deltaY");case"set-interaction-mode":return i(t)&&S(t,"enabled");case"set-selection-visual":return i(t)&&d(t,"version",R)&&p(n(t,"ref"))&&d(t,"visible",!0);case"clear-selection-visual":return i(t)&&d(t,"version",R);case"set-resize-visual":return i(t)&&d(t,"version",w)&&p(n(t,"ref"))&&d(t,"visible",!0);case"clear-resize-visual":return i(t)&&d(t,"version",w);case"set-theme-override":return ee(t);case"get-theme-variables":return i(t)&&A(n(t,"names"));case"compute-drop-target-at-point":return i(t)&&o(t,"x")&&o(t,"y")&&(d(t,"dragKind","insert")||d(t,"dragKind","move"))&&(a(t,"movingRef")||p(n(t,"movingRef")));case"observe-node-bounds":case"clear-node-bounds-observer":return i(t)&&(a(t,"ref")||p(n(t,"ref")));case"apply-node-patch":return i(t)&&p(n(t,"ref"))&&Q(n(t,"patch"))&&(a(t,"preview")||i(n(t,"preview"))&&s(n(t,"preview"),"sessionId")&&b(n(t,"preview"),"revision")&&l(n(t,"preview"),"revision"));case"get-hit-by-ref":case"get-path-by-ref":case"restore-text-edit":case"clear-text-edit-rollback":return v(t);case"bridge-initialize-session":case"bridge-get-style-context":return i(t)&&s(t,"routeId");case"bridge-get-document":case"bridge-ensure-document-version":case"bridge-acknowledge-document-version":return i(t)&&s(t,"routeId")&&y(t,"minVersion")&&y(t,"version");case"bridge-execute":return i(t)&&i(n(t,"request"));case"bridge-subscribe":case"bridge-unsubscribe":return i(t)&&s(t,"subscriptionId");default:return!1}}function re(e){return d(e,"type","response")&&s(e,"id")&&S(e,"ok")&&(a(e,"error")||s(e,"error"))}var ne=new Set(["pointer-down","pointer-move","pointer-leave","pointer-up","pointer-cancel","pointer-click","pointer-double-click"]),F=new Set(["e","s","se"]);function ie(e,r){if(a(e,"resizeSession"))return!0;let t=n(e,"resizeSession");if(!i(t))return!1;let c=n(e,"pointerId"),f=n(t,"pointerId"),E=n(t,"phase"),m=n(t,"edge"),D=r==="pointer-down"?"start":r==="pointer-up"?"commit":r==="pointer-cancel"?"cancel":null;return n(t,"version")===1&&E===D&&s(t,"sessionId")&&String(n(t,"sessionId")).length>0&&typeof c=="number"&&Number.isInteger(c)&&typeof f=="number"&&Number.isInteger(f)&&c===f&&typeof m=="string"&&F.has(m)&&n(e,"resizeEdge")===m&&p(n(t,"ref"))&&["startWidth","startHeight","width","height"].every(P=>o(t,P))}function se(e){if(!d(e,"type","event")||!s(e,"kind")||!i(n(e,"payload")))return!1;let r=n(e,"kind"),t=n(e,"payload");switch(r){case"text-edit-commit":case"text-edit-cancel":case"text-edit-exit":case"text-edit-input":return p(n(t,"ref"))&&g(t,"value")&&(a(t,"hit")||I(n(t,"hit")));case"node-bounds-change":return I(n(t,"hit"));case"geometry-batch":{let c=n(t,"reason");return K(t,"sequence")&&o(t,"sourceEventAt")&&o(t,"captureStartedAt")&&o(t,"capturedAt")&&(c==="scroll"||c==="resize"||c==="mutation")&&Y(n(t,"snapshots"))}case"bridge-event":return s(t,"subscriptionId")&&i(n(t,"event"));case"route-ready":return s(t,"routeId")&&y(t,"version");case"bridge-status":{let c=n(t,"state");return(c==="connecting"||c==="ready"||c==="reconnecting"||c==="failed"||c==="reload-required")&&g(t,"routeId")&&y(t,"attempt")&&y(t,"retryInMs")&&g(t,"messageKey")}case"scroll":{let c=n(t,"metrics");return i(c)&&["scrollX","scrollY","scrollWidth","scrollHeight","viewportWidth","viewportHeight"].every(f=>o(c,f))}default:return ne.has(r)&&o(t,"clientX")&&o(t,"clientY")&&y(t,"buttons")&&y(t,"pointerId")&&(a(t,"hoverVisualOwned")||S(t,"hoverVisualOwned"))&&(a(t,"resizeEdge")||s(t,"resizeEdge")&&F.has(n(t,"resizeEdge")))&&ie(t,r)&&(n(t,"hit")===null||I(n(t,"hit")))&&(a(t,"section")||n(t,"section")===null||B(n(t,"section")))&&(a(t,"sectionGap")||n(t,"sectionGap")===null||L(n(t,"sectionGap")))}}function oe(e){if(!i(e))return!1;switch(n(e,"type")){case"request":return te(e);case"response":return re(e);case"event":return se(e);default:return!1}}export{N as SITE_EDIT_FRAME_RUNTIME_CHANNEL,C as SITE_EDIT_FRAME_RUNTIME_LAYOUT_SNAPSHOT_VERSION,w as SITE_EDIT_FRAME_RUNTIME_RESIZE_VISUAL_VERSION,R as SITE_EDIT_FRAME_RUNTIME_SELECTION_VISUAL_VERSION,ae as SITE_EDIT_FRAME_SECTION_GAP_RADIUS_PX,O as SITE_EDIT_WINDOW_MESSAGE_NAMESPACE,_ as VCP_WINDOW_MESSAGE_SOURCE,ce as VCP_WINDOW_MESSAGE_VERSION,de as createSiteEditFrameRuntimeMessage,M as createVcpWindowMessageEnvelope,x as isSiteEditFrameRuntimeLayoutSnapshot,ue as isSiteEditFrameRuntimeMessage,W as isVcpWindowMessageEnvelope};
1
+ function S(e){return JSON.stringify([e.routeId,e.effectiveTemplateId??null])}var T="vcp-window-message",F=1;function B(e){return{source:T,version:F,namespace:e.namespace,channel:e.channel,...e.sessionKey?{sessionKey:e.sessionKey}:{},body:e.body}}function G(e){try{return i(e)?d(e,"source",T)&&d(e,"version",F)&&o(e,"namespace")&&o(e,"channel")&&f(e,"body")&&(!h(e,"sessionKey")||o(e,"sessionKey")):!1}catch{return!1}}var V="site-edit",C="frame-runtime",z=1,A=1,N=1,le=24;function ge(e,r={}){return B({namespace:V,channel:C,sessionKey:r.sessionKey,body:e})}function he(e){try{return!G(e)||e.namespace!==V||e.channel!==C?!1:ue(e.body)}catch{return!1}}function y(e){return i(e)&&o(e,"routeId")&&g(e,"templateId")&&m(e,["routeId","templateId"])}function R(e){return i(e)&&o(e,"routeId")&&g(e,"effectiveTemplateId")&&m(e,["routeId","effectiveTemplateId"])}function m(e,r){let t=new Set(r);return Reflect.ownKeys(e).every(s=>typeof s=="string"&&t.has(s))}var h=(e,r)=>Object.prototype.hasOwnProperty.call(e,r);function f(e,r){let t=Object.getOwnPropertyDescriptor(e,r);return t!==void 0&&"value"in t}function n(e,r){return Object.getOwnPropertyDescriptor(e,r)?.value}function d(e,r,t){return f(e,r)&&n(e,r)===t}function o(e,r){return f(e,r)&&typeof n(e,r)=="string"}function _(e,r){return f(e,r)&&typeof n(e,r)=="boolean"}function c(e,r){let t=n(e,r);return f(e,r)&&typeof t=="number"&&Number.isFinite(t)}function q(e,r){let t=n(e,r);return f(e,r)&&typeof t=="number"&&Number.isInteger(t)&&t>0}function g(e,r){return!h(e,r)||n(e,r)===void 0||o(e,r)}function b(e,r){return!h(e,r)||n(e,r)===void 0||c(e,r)}function w(e,r){let t=n(e,r);return!h(e,r)||t===void 0||f(e,r)&&typeof t=="number"&&Number.isInteger(t)&&t>=0}function a(e,r){return!h(e,r)||n(e,r)===void 0}function i(e){if(typeof e!="object"||e===null||Array.isArray(e))return!1;let r=Object.getPrototypeOf(e);return r===Object.prototype||r===null}function U(e){return i(e)&&Reflect.ownKeys(e).length===0}function O(e){if(!Array.isArray(e))return!1;for(let r=0;r<e.length;r+=1){let t=Object.getOwnPropertyDescriptor(e,String(r));if(t===void 0||!("value"in t)||typeof t.value!="string")return!1}return!0}function u(e){return i(e)&&o(e,"key")&&w(e,"instanceIndex")&&w(e,"instanceCount")&&w(e,"textSegmentIndex")}function j(e){return i(e)&&o(e,"blockId")&&u(n(e,"ref"))&&E(n(e,"rect"))&&_(e,"targetIsSectionRoot")}function H(e){if(!i(e))return!1;let r=n(e,"placement"),t=n(e,"boundary");return o(e,"anchorBlockId")&&u(n(e,"anchorRef"))&&(r==="before"||r==="after")&&i(t)&&c(t,"top")&&c(t,"left")&&c(t,"width")}function E(e){return i(e)&&["top","left","width","height"].every(r=>c(e,r))}function P(e){if(!i(e))return!1;let r=n(e,"rect"),t=n(e,"layout"),s=i(t)?n(t,"containingBlock"):null,p=n(e,"scrollContext"),l=i(s)&&(d(s,"kind","viewport")&&Reflect.ownKeys(s).length===1||d(s,"kind","document")&&Reflect.ownKeys(s).length===1||d(s,"kind","element")&&o(s,"runtimeNodeId"));return d(e,"version",z)&&o(e,"runtimeNodeId")&&i(r)&&E(n(r,"viewport"))&&E(n(r,"document"))&&i(t)&&o(t,"position")&&o(t,"transform")&&l&&i(p)&&["scrollX","scrollY","viewportWidth","viewportHeight"].every(I=>c(p,I))&&f(p,"scrollContainers")&&X(n(p,"scrollContainers"))}function X(e){return Array.isArray(e)&&e.every(r=>i(r)&&o(r,"runtimeNodeId")&&c(r,"scrollLeft")&&c(r,"scrollTop"))}function x(e){return i(e)&&(a(e,"layoutSnapshot")||P(n(e,"layoutSnapshot")))}function Y(e){return i(e)&&u(n(e,"ref"))&&f(e,"layoutSnapshot")&&P(n(e,"layoutSnapshot"))&&(a(e,"childBoxes")||J(n(e,"childBoxes")))&&(a(e,"childRects")||Z(n(e,"childRects")))&&(a(e,"layout")||k(n(e,"layout")))&&(a(e,"spacing")||Q(n(e,"spacing")))}function k(e){if(!i(e))return!1;let r=n(e,"indicatorOrientation");return o(e,"display")&&(r==="horizontal"||r==="vertical")&&g(e,"flexDirection")&&g(e,"gridAutoFlow")}function Z(e){return Array.isArray(e)&&e.every(r=>E(r))}function J(e){return Array.isArray(e)&&e.every(r=>i(r)&&E(n(r,"rect"))&&D(n(r,"margin")))}function D(e){return i(e)&&["marginTop","marginRight","marginBottom","marginLeft"].every(r=>c(e,r))}function Q(e){return D(e)&&["paddingTop","paddingRight","paddingBottom","paddingLeft","borderTopWidth","borderRightWidth","borderBottomWidth","borderLeftWidth","columnGap","rowGap"].every(r=>c(e,r))}function $(e){if(!Array.isArray(e))return!1;for(let r=0;r<e.length;r+=1){let t=Object.getOwnPropertyDescriptor(e,String(r));if(t===void 0||!("value"in t)||!Y(t.value))return!1}return!0}function v(e){return i(e)&&Reflect.ownKeys(e).every(r=>typeof r=="string"&&f(e,r)&&(typeof n(e,r)=="string"||n(e,r)===null))}function K(e){return e==null||typeof e=="string"||typeof e=="number"&&Number.isFinite(e)}function ee(e){return i(e)&&Reflect.ownKeys(e).every(r=>typeof r=="string"&&f(e,r)&&K(n(e,r)))}function te(e){if(!i(e))return!1;let r=n(e,"priority");return o(e,"property")&&f(e,"value")&&K(n(e,"value"))&&(!h(e,"priority")||r===void 0||r==="important")}function re(e){return i(e)?(a(e,"attributes")||v(n(e,"attributes")))&&g(e,"className")&&(a(e,"style")||ee(n(e,"style")))&&(a(e,"styleDeclarations")||Array.isArray(n(e,"styleDeclarations"))&&n(e,"styleDeclarations").every(te)):!1}function ne(e){return i(e)&&c(e,"x")&&c(e,"y")&&(a(e,"detailLevel")||d(e,"detailLevel","summary")||d(e,"detailLevel","full"))}function ie(e){return i(e)&&u(n(e,"ref"))}function oe(e){if(!i(e)||!i(n(e,"variables")))return!1;let r=n(e,"variables");return Reflect.ownKeys(r).every(t=>typeof t=="string"&&o(r,t))?a(e,"stylesheets")||O(n(e,"stylesheets")):!1}function se(e){if(!d(e,"type","request")||!o(e,"id")||!o(e,"kind")||!f(e,"payload"))return!1;let r=n(e,"kind"),t=n(e,"payload");switch(r){case"hit-test-at-point":case"start-text-edit-at-point":return ne(t);case"bridge-get-source-tree":return i(t)&&y(n(t,"composition"))&&m(t,["composition"]);case"get-scroll-metrics":case"clear-theme-override":return U(t);case"bridge-get-history-status":case"bridge-undo":case"bridge-redo":return i(t)&&y(n(t,"composition"))&&m(t,["composition"]);case"bridge-get-source-file":return i(t)&&o(t,"path")&&y(n(t,"composition"))&&m(t,["path","composition"]);case"bridge-resolve-source-location":case"bridge-get-object-edit-context":case"bridge-get-class-name-source":return i(t)&&o(t,"key")&&y(n(t,"composition"))&&m(t,["key","composition"]);case"scroll-to":return i(t)&&c(t,"x")&&c(t,"y");case"scroll-by":return i(t)&&c(t,"deltaX")&&c(t,"deltaY");case"set-interaction-mode":return i(t)&&_(t,"enabled");case"set-selection-visual":return i(t)&&d(t,"version",A)&&u(n(t,"ref"))&&d(t,"visible",!0);case"clear-selection-visual":return i(t)&&d(t,"version",A);case"set-resize-visual":return i(t)&&d(t,"version",N)&&u(n(t,"ref"))&&d(t,"visible",!0);case"clear-resize-visual":return i(t)&&d(t,"version",N);case"set-theme-override":return oe(t);case"get-theme-variables":return i(t)&&O(n(t,"names"));case"compute-drop-target-at-point":return i(t)&&c(t,"x")&&c(t,"y")&&(d(t,"dragKind","insert")||d(t,"dragKind","move"))&&(a(t,"movingRef")||u(n(t,"movingRef")));case"observe-node-bounds":case"clear-node-bounds-observer":return i(t)&&(a(t,"ref")||u(n(t,"ref")));case"apply-node-patch":return i(t)&&u(n(t,"ref"))&&re(n(t,"patch"))&&(a(t,"preview")||i(n(t,"preview"))&&o(n(t,"preview"),"sessionId")&&w(n(t,"preview"),"revision")&&h(n(t,"preview"),"revision"));case"get-hit-by-ref":case"get-path-by-ref":case"restore-text-edit":case"clear-text-edit-rollback":return ie(t);case"bridge-initialize-session":case"bridge-get-style-context":return i(t)&&y(n(t,"composition"))&&m(t,["composition"]);case"bridge-get-document":case"bridge-ensure-document-version":case"bridge-acknowledge-document-version":return i(t)&&y(n(t,"composition"))&&b(t,"minVersion")&&b(t,"version")&&m(t,["composition","minVersion","version"]);case"bridge-execute":{if(!i(t))return!1;let s=n(t,"request"),p=n(t,"composition"),l=i(s)?n(s,"composition"):null;return!y(p)||!i(s)||!y(l)?!1:S({routeId:p.routeId,...p.templateId?{effectiveTemplateId:p.templateId}:{}})===S({routeId:l.routeId,...l.templateId?{effectiveTemplateId:l.templateId}:{}})&&m(t,["composition","request"])}case"bridge-subscribe":case"bridge-unsubscribe":return i(t)&&o(t,"subscriptionId")&&y(n(t,"composition"))&&m(t,["subscriptionId","composition"]);default:return!1}}function ce(e){return d(e,"type","response")&&o(e,"id")&&_(e,"ok")&&(a(e,"error")||o(e,"error"))}function ae(e){if(!i(e))return!1;let r=n(e,"type");if(typeof r!="string"||!R(n(e,"composition"))||!o(e,"siteId")||!o(e,"at"))return!1;switch(r){case"site-edit.document.changed":return o(e,"snapshotId")&&c(e,"version");case"site-edit.operation.planned":return o(e,"operationId")&&o(e,"baseSnapshotId")&&O(n(e,"changedFiles"));case"site-edit.operation.completed":return i(n(e,"result"));case"site-edit.operation.failed":return o(e,"requestId")&&i(n(e,"error"));case"site-edit.capability.changed":return O(n(e,"keys"));case"site-edit.graph.invalidated":return!0;case"site-edit.graph.ready":return c(e,"version");case"site-edit.graph.error":return o(e,"message");default:return!1}}var de=new Set(["pointer-down","pointer-move","pointer-leave","pointer-up","pointer-cancel","pointer-click","pointer-double-click"]),M=new Set(["e","s","se"]);function pe(e,r){if(a(e,"resizeSession"))return!0;let t=n(e,"resizeSession");if(!i(t))return!1;let s=n(e,"pointerId"),p=n(t,"pointerId"),l=n(t,"phase"),I=n(t,"edge"),L=r==="pointer-down"?"start":r==="pointer-up"?"commit":r==="pointer-cancel"?"cancel":null;return n(t,"version")===1&&l===L&&o(t,"sessionId")&&String(n(t,"sessionId")).length>0&&typeof s=="number"&&Number.isInteger(s)&&typeof p=="number"&&Number.isInteger(p)&&s===p&&typeof I=="string"&&M.has(I)&&n(e,"resizeEdge")===I&&u(n(t,"ref"))&&["startWidth","startHeight","width","height"].every(W=>c(t,W))}function fe(e){if(!d(e,"type","event")||!o(e,"kind")||!i(n(e,"payload")))return!1;let r=n(e,"kind"),t=n(e,"payload");switch(r){case"text-edit-commit":case"text-edit-cancel":case"text-edit-exit":case"text-edit-input":return u(n(t,"ref"))&&g(t,"value")&&(a(t,"hit")||x(n(t,"hit")));case"node-bounds-change":return x(n(t,"hit"));case"geometry-batch":{let s=n(t,"reason");return q(t,"sequence")&&c(t,"sourceEventAt")&&c(t,"captureStartedAt")&&c(t,"capturedAt")&&(s==="scroll"||s==="resize"||s==="mutation")&&$(n(t,"snapshots"))}case"bridge-event":{let s=n(t,"event"),p=n(t,"composition");return!ae(s)||!R(p)?!1:o(t,"subscriptionId")&&S(p)===S(s.composition)}case"route-ready":return R(n(t,"composition"))&&o(t,"editEngineVersion")&&c(t,"sequence")&&c(t,"version");case"bridge-status":{let s=n(t,"state");return(s==="connecting"||s==="ready"||s==="reconnecting"||s==="failed"||s==="reload-required")&&R(n(t,"composition"))&&c(t,"sequence")&&b(t,"attempt")&&b(t,"retryInMs")&&g(t,"messageKey")}case"scroll":{let s=n(t,"metrics");return i(s)&&["scrollX","scrollY","scrollWidth","scrollHeight","viewportWidth","viewportHeight"].every(p=>c(s,p))}default:return de.has(r)&&c(t,"clientX")&&c(t,"clientY")&&b(t,"buttons")&&b(t,"pointerId")&&(a(t,"hoverVisualOwned")||_(t,"hoverVisualOwned"))&&(a(t,"resizeEdge")||o(t,"resizeEdge")&&M.has(n(t,"resizeEdge")))&&pe(t,r)&&(n(t,"hit")===null||x(n(t,"hit")))&&(a(t,"section")||n(t,"section")===null||j(n(t,"section")))&&(a(t,"sectionGap")||n(t,"sectionGap")===null||H(n(t,"sectionGap")))}}function ue(e){if(!i(e))return!1;switch(n(e,"type")){case"request":return se(e);case"response":return ce(e);case"event":return fe(e);default:return!1}}export{C as SITE_EDIT_FRAME_RUNTIME_CHANNEL,z as SITE_EDIT_FRAME_RUNTIME_LAYOUT_SNAPSHOT_VERSION,N as SITE_EDIT_FRAME_RUNTIME_RESIZE_VISUAL_VERSION,A as SITE_EDIT_FRAME_RUNTIME_SELECTION_VISUAL_VERSION,le as SITE_EDIT_FRAME_SECTION_GAP_RADIUS_PX,V as SITE_EDIT_WINDOW_MESSAGE_NAMESPACE,T as VCP_WINDOW_MESSAGE_SOURCE,F as VCP_WINDOW_MESSAGE_VERSION,ge as createSiteEditFrameRuntimeMessage,B as createVcpWindowMessageEnvelope,P as isSiteEditFrameRuntimeLayoutSnapshot,he as isSiteEditFrameRuntimeMessage,G as isVcpWindowMessageEnvelope};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcp-dev/site-edit-bridge",
3
- "version": "0.6.10",
3
+ "version": "0.7.0",
4
4
  "type": "module",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -74,8 +74,8 @@
74
74
  "typecheck": "tsc -p tsconfig.json --noEmit"
75
75
  },
76
76
  "dependencies": {
77
- "@vcp-dev/contracts": "0.6.10",
78
- "@vcp-dev/site-edit-engine": "0.6.10",
77
+ "@vcp-dev/contracts": "0.7.0",
78
+ "@vcp-dev/site-edit-engine": "0.7.0",
79
79
  "@types/ws": "^8.18.1",
80
80
  "ws": "^8.20.1"
81
81
  },