@vcp-dev/site-edit-bridge 0.6.11 → 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;
@@ -115,7 +115,8 @@ export type SiteEditFrameRuntimeDropTarget = {
115
115
  export type SiteEditFrameRuntimeBridgeStatusCode = "connecting" | "ready" | "reconnecting" | "failed" | "reload-required";
116
116
  export type SiteEditFrameRuntimeBridgeStatus = {
117
117
  state: SiteEditFrameRuntimeBridgeStatusCode;
118
- routeId?: string;
118
+ composition: SiteEditCompositionContext;
119
+ sequence: number;
119
120
  attempt?: number;
120
121
  retryInMs?: number;
121
122
  messageKey?: string;
@@ -133,13 +134,16 @@ export type SiteEditFrameRuntimeRequestBody = {
133
134
  type: "request";
134
135
  id: string;
135
136
  kind: "bridge-get-source-tree";
136
- payload: Record<string, never>;
137
+ payload: {
138
+ composition: SiteEditCompositionSelector;
139
+ };
137
140
  } | {
138
141
  type: "request";
139
142
  id: string;
140
143
  kind: "bridge-get-source-file";
141
144
  payload: {
142
145
  path: string;
146
+ composition: SiteEditCompositionSelector;
143
147
  };
144
148
  } | {
145
149
  type: "request";
@@ -147,7 +151,7 @@ export type SiteEditFrameRuntimeRequestBody = {
147
151
  kind: "bridge-resolve-source-location";
148
152
  payload: {
149
153
  key: string;
150
- routeId?: string;
154
+ composition: SiteEditCompositionSelector;
151
155
  };
152
156
  } | {
153
157
  type: "request";
@@ -271,14 +275,14 @@ export type SiteEditFrameRuntimeRequestBody = {
271
275
  id: string;
272
276
  kind: "bridge-initialize-session";
273
277
  payload: {
274
- routeId: string;
278
+ composition: SiteEditCompositionSelector;
275
279
  };
276
280
  } | {
277
281
  type: "request";
278
282
  id: string;
279
283
  kind: "bridge-get-document" | "bridge-ensure-document-version" | "bridge-acknowledge-document-version";
280
284
  payload: {
281
- routeId: string;
285
+ composition: SiteEditCompositionSelector;
282
286
  minVersion?: number;
283
287
  version?: number;
284
288
  };
@@ -286,13 +290,15 @@ export type SiteEditFrameRuntimeRequestBody = {
286
290
  type: "request";
287
291
  id: string;
288
292
  kind: "bridge-get-history-status";
289
- payload: Record<string, never>;
293
+ payload: {
294
+ composition: SiteEditCompositionSelector;
295
+ };
290
296
  } | {
291
297
  type: "request";
292
298
  id: string;
293
299
  kind: "bridge-get-style-context";
294
300
  payload: {
295
- routeId: string;
301
+ composition: SiteEditCompositionSelector;
296
302
  };
297
303
  } | {
298
304
  type: "request";
@@ -300,26 +306,30 @@ export type SiteEditFrameRuntimeRequestBody = {
300
306
  kind: "bridge-get-object-edit-context" | "bridge-get-class-name-source";
301
307
  payload: {
302
308
  key: string;
303
- routeId?: string;
309
+ composition: SiteEditCompositionSelector;
304
310
  };
305
311
  } | {
306
312
  type: "request";
307
313
  id: string;
308
314
  kind: "bridge-execute";
309
315
  payload: {
316
+ composition: SiteEditCompositionSelector;
310
317
  request: SiteEditOperationRequest;
311
318
  };
312
319
  } | {
313
320
  type: "request";
314
321
  id: string;
315
322
  kind: "bridge-undo" | "bridge-redo";
316
- payload: Record<string, never>;
323
+ payload: {
324
+ composition: SiteEditCompositionSelector;
325
+ };
317
326
  } | {
318
327
  type: "request";
319
328
  id: string;
320
329
  kind: "bridge-subscribe" | "bridge-unsubscribe";
321
330
  payload: {
322
331
  subscriptionId: string;
332
+ composition: SiteEditCompositionSelector;
323
333
  };
324
334
  };
325
335
  export type SiteEditFrameRuntimeMargin = {
@@ -502,6 +512,7 @@ export type SiteEditFrameRuntimeEventBody = {
502
512
  kind: "bridge-event";
503
513
  payload: {
504
514
  subscriptionId: string;
515
+ composition: SiteEditCompositionContext;
505
516
  event: SiteEditEvent;
506
517
  };
507
518
  } | {
@@ -523,8 +534,10 @@ export type SiteEditFrameRuntimeEventBody = {
523
534
  type: "event";
524
535
  kind: "route-ready";
525
536
  payload: {
526
- routeId: string;
527
- version?: number;
537
+ composition: SiteEditCompositionContext;
538
+ editEngineVersion: string;
539
+ sequence: number;
540
+ version: number;
528
541
  };
529
542
  } | {
530
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.11",
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.11",
78
- "@vcp-dev/site-edit-engine": "0.6.11",
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
  },