@vcp-dev/site-edit-bridge 0.10.28 → 0.10.30

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.
@@ -1,7 +1,7 @@
1
- import xe from"node:http";import{existsSync as F,readFileSync as U}from"node:fs";import{randomUUID as Zt}from"node:crypto";import{createRequire as Le}from"node:module";import{Socket as We}from"node:net";import z from"node:path";import{basename as qe,dirname as J,join as G}from"node:path";import{fileURLToPath as ze}from"node:url";import{createRequire as Kt}from"node:module";import{pathToFileURL as Wt}from"node:url";import{Worker as $t}from"node:worker_threads";var ve=["resolveComposition","initializeSession","getDocument","getHistoryStatus","getStyleContext","getObjectEditContext","getClassNameSource","getSourceTree","getSourceFile","resolveSourceLocation","execute","undo","redo"];function ne(e){let t=new Error(e.message);return t.name=e.name,e.code!==void 0&&(t.code=e.code),t}import dt from"node:http";import q from"node:fs";import{createHash as Oe,randomBytes as ht,timingSafeEqual as pt}from"node:crypto";import b from"node:path";import{WebSocket as Me,WebSocketServer as lt}from"ws";import{createPreviewSiteEditEngineRuntime as ft,openFileHistoryStore as gt,resolveManagedPageTemplateComposition as mt,scanSiteEditCompositionsFromFiles as yt}from"@vcp-dev/site-edit-engine";import{resolveNextAppRouteId as St,scanNextAppRouterRoutesFromFiles as It}from"@vcp-dev/site-edit-engine/next-app-router";import{SiteEditSourceWatcher as Et}from"@vcp-dev/site-edit-engine/source-watcher";function Re(e){let t=new Map,n=[],i=new Map,s=[],o=e.pageComposition.status==="supported"?e.pageComposition.placementUnitKeys:[],r=new Map(o.map((d,f)=>[d,f])),c=e.pageComposition.status==="supported"?{status:"supported",containerKey:e.pageComposition.containerKey,hasBusinessMembers:e.pageComposition.hasBusinessMembers,placementUnitKeys:e.pageComposition.placementUnitKeys,placements:e.pageComposition.placements.map(d=>({placementKey:d.placementKey,placementUnitKey:d.placementUnitKey,relation:d.relation}))}:{status:"unsupported",reason:e.pageComposition.reason,diagnostics:e.pageComposition.diagnostics},p=e.entries.flatMap((d,f)=>d.dynamicDataSummary?[[f,d.dynamicDataSummary]]:[]),a=new Map(e.entries.map((d,f)=>[d.key,f])),l=[];for(let[d,f]of e.entries.entries()){let m=f.pageCompositionActionScope;if(!m)continue;if(m.kind!=="source-siblings"){l.push([d,{kind:m.kind}]);continue}let x=m.siblingKeys.map(E=>{let w=a.get(E);if(w===void 0)throw new Error("Render entry "+f.key+" references missing source sibling "+E);return w});l.push([d,{kind:"source-siblings",siblingEntryIndexes:x}])}let u=d=>{let f=t.get(d);if(typeof f=="number")return f;let m=n.length;return n.push(d),t.set(d,m),m},S=d=>{let f=null;for(let m of tt(d)){let x=`${f??"root"}\0${m}`,E=i.get(x);if(typeof E=="number"){f=E;continue}let w=s.length;s.push([f,u(m)]),i.set(x,w),f=w}if(f===null)throw new Error("Document key must not be empty");return f};return{encoding:"segment-trie-v1",siteId:e.siteId,snapshotId:e.snapshotId,composition:{...e.composition},routeId:e.composition.routeId,version:e.version,pageComposition:c,tokens:n,nodes:s,entries:e.entries.map(d=>{let f=d.pageCompositionUnitKey?r.get(d.pageCompositionUnitKey)??-1:-1;if(d.pageCompositionUnitKey&&f<0)throw new Error(`Render entry ${d.key} references unknown page composition unit ${d.pageCompositionUnitKey}`);return[S(d.key),et(d.operationSummary),...f>=0?[f]:[]]}),...l.length>0?{pageCompositionActionScopes:l}:{},...e.entries.every(d=>d.parentKey!==void 0)?{entryParentNodeIds:e.entries.map(d=>d.parentKey===null?null:S(d.parentKey))}:{},...p.length>0?{dynamicDataSummaries:p}:{}}}function et(e){return(e.canUpdateText?1:0)|(e.canInsertChild?2:0)|(e.canMove?4:0)|(e.canRemove?8:0)}function tt(e){if(!e)return[];let t=[],n=0,i=be(e,n);if(i<0)return t.push(e),t;for(t.push(e.slice(0,i)),n=i;n<e.length;){if(i=be(e,n+(e.startsWith("::",n)?2:1)),i<0){t.push(e.slice(n));break}t.push(e.slice(n,i)),n=i}return t}function be(e,t){let n=e.indexOf("/",t),i=e.indexOf("::",t);return n<0?i:i<0?n:Math.min(n,i)}var _e="SITE_EDIT_COMPOSITION_SESSION_MISMATCH",ue="SITE_EDIT_COMPOSITION_SESSION_REQUIRED";var v=class e{constructor(){}static parseMessage(t,n={}){let i=JSON.parse(t);if(!e.isMessage(i,n))throw new Error("Invalid site edit bridge message");return i}static stringifyMessage(t){return JSON.stringify(t)}static extractRequestInfo(t){if(y(t)&&y(t.payload)){let n=typeof t.payload.id=="string"?t.payload.id:"unknown",i=this.isRequestKind(t.payload.kind)?t.payload.kind:"get-document";return{id:n,kind:i}}return{id:"unknown",kind:"get-document"}}static isRequestKind(t){return t==="initialize-session"||t==="get-document"||t==="get-history-status"||t==="get-style-context"||t==="get-object-edit-context"||t==="get-class-name-source"||t==="get-source-tree"||t==="get-source-file"||t==="resolve-source-location"||t==="execute"||t==="undo"||t==="redo"}static isMessage(t,n={}){return!y(t)||typeof t.type!="string"?!1:t.type==="request"?nt(t.payload,n):t.type==="response"||t.type==="error"?y(t.payload)&&typeof t.payload.id=="string":t.type==="event"?y(t.payload)&&y(t.payload.event):t.type==="auth"?y(t.payload)&&typeof t.payload.key=="string":t.type==="auth-ok"&&y(t.payload)&&t.payload.ok===!0}},Q=class{constructor(t){this.options=t,this.session={subscribedCompositionKeys:new Set},this.messageQueue=new ce,this.eventDispatcher=new ae(n=>{this.sendJson(n)}),this.unsubscribe=t.engine.subscribe(n=>{this.handleEngineEvent(n)}),t.socket.onmessage=n=>{try{this.messageQueue.enqueue(()=>this.handleRawMessage(n.data))}catch(i){this.sendJson({type:"error",payload:{id:"unknown",kind:"get-document",message:i instanceof Error?i.message:"Bridge queue overflow"}}),t.socket.close(1013,"bridge busy")}},t.socket.onclose=()=>{this.unsubscribe(),this.session.activeComposition=void 0,this.session.subscribedCompositionKeys.clear()}}async handleMessage(t){try{let n=t;if(n.type!=="request")return;let i=n.payload,{id:s}=i;switch(i.kind){case"initialize-session":{let o=ie(i),r=await this.resolve(o),c=await this.options.engine.initializeSession({composition:r.context,...i.mutationContext?{mutationContext:i.mutationContext}:{}});this.activateSession(r.context),this.sendJson({type:"response",payload:{id:s,kind:i.kind,result:H({...c,data:{...c.data,document:Te(c.data.document)}},r.context)}});return}case"get-document":{let o=await this.resolveWireContext(i),r=await this.options.engine.getDocument(o);this.sendResult(s,i.kind,ct(r,o));return}case"get-history-status":{let o=await this.resolveWireContext(i),r=await this.options.engine.getHistoryStatus(o);this.sendResult(s,i.kind,H(r,o));return}case"get-style-context":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,H(await this.options.engine.getStyleContext(o),o));return}case"get-object-edit-context":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,H(await this.options.engine.getObjectEditContext(i.key,o,i.selectionRef),o));return}case"get-class-name-source":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,H(await this.options.engine.getClassNameSource(i.key,o),o));return}case"get-source-tree":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,H(await this.options.engine.getSourceTree(o),o));return}case"get-source-file":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,H(await this.options.engine.getSourceFile({path:i.path,composition:o}),o));return}case"resolve-source-location":{let o=await this.resolveWireContext(i),r=H(await this.options.engine.resolveSourceLocation({key:i.key,composition:o}),o);this.sendResult(s,i.kind,r);return}case"execute":{let o=await this.resolveOperationWireContext(i.request),r=await this.resolveWireContext(i);if(N(o)!==N(r))throw new O(_e,"The execute request composition does not match its operation composition.");let c=await this.normalizeOperationRequest(i.request,o);await this.handleBufferedOperation(s,i.kind,()=>this.options.engine.execute(c));return}case"undo":case"redo":{let o=await this.resolveWireContext(i);await this.handleBufferedOperation(s,i.kind,()=>i.kind==="undo"?this.options.engine.undo(o):this.options.engine.redo(o));return}}}catch(n){let i=v.extractRequestInfo(t);this.sendJson({type:"error",payload:{...i,message:re(n),code:oe(n)}})}}async resolve(t){return this.options.engine.resolveComposition(t)}async resolveAndAssert(t){let n=await this.resolve(t),i=this.session.activeComposition;if(!i)throw new O(ue,"Initialize a composition session before issuing this request.");if(N(i)!==N(n.context))throw new O(_e,"The request composition does not match the active socket session.");return n.context}async resolveWireContext(t){let n=ie(t);return this.resolveAndAssert(n)}async resolveOperationWireContext(t){let n=rt(t);return this.resolveAndAssert(n)}activateSession(t){this.session.activeComposition=t,this.session.subscribedCompositionKeys.clear(),this.session.subscribedCompositionKeys.add(N(t))}async normalizeOperationRequest(t,n){let i={...t,composition:ke(n)};if(i.target.kind==="route"){let s=i.target,o=ie(s),r=await this.resolveAndAssert(o);i.target={...s,composition:ke(r)}}return i}handleEngineEvent(t){let n=t?.composition;if(!ot(n))return;let i=N(n);this.session.subscribedCompositionKeys.has(i)&&(this.eventDispatcher.push(t),t.type==="site-edit.graph.invalidated"&&i===at(this.session)&&(this.session.activeComposition=void 0,this.session.subscribedCompositionKeys.delete(i)))}sendResult(t,n,i){this.sendJson({type:"response",payload:{id:t,kind:n,result:i}})}async handleRawMessage(t){try{await this.handleMessage(v.parseMessage(t,{validateOperationRequest:this.options.validateOperationRequest}))}catch(n){let i=ut(t);this.sendJson({type:"error",payload:{...i,message:re(n),code:oe(n)}})}}sendJson(t){this.options.socket.send(v.stringifyMessage(t))}async handleBufferedOperation(t,n,i){this.eventDispatcher.beginBuffering();try{let s=await i();this.sendResult(t,n,s)}catch(s){this.sendJson({type:"error",payload:{id:t,kind:n,message:re(s),code:oe(s)}})}finally{this.eventDispatcher.flush()}}},O=class extends Error{constructor(t,n){super(n),this.code=t,this.name="BridgeProtocolError"}},ae=class{constructor(t){this.send=t,this.bufferedEvents=null}push(t){let n={type:"event",payload:{event:t}};if(this.bufferedEvents){this.bufferedEvents.push(n);return}this.send(n)}beginBuffering(){this.bufferedEvents=[]}flush(){let t=this.bufferedEvents??[];this.bufferedEvents=null,t.forEach(n=>this.send(n))}},ce=class{constructor(t=64){this.maxQueued=t,this.queue=Promise.resolve(),this.queued=0}enqueue(t){if(this.queued>=this.maxQueued)throw new Error("Bridge request queue is full");this.queued+=1;let n=async()=>{this.queued-=1,await t()},i=this.queue.then(n,n);return this.queue=i.then(()=>{},()=>{}),i}};function nt(e,t){if(!y(e)||typeof e.id!="string"||!v.isRequestKind(e.kind))return!1;let n=L(e.composition);switch(e.kind){case"initialize-session":return n&&(e.mutationContext===void 0||se(e.mutationContext));case"get-document":case"get-style-context":return n;case"get-object-edit-context":return typeof e.key=="string"&&n&&it(e.selectionRef);case"get-class-name-source":case"resolve-source-location":return typeof e.key=="string"&&n;case"get-history-status":return n;case"get-source-tree":return n;case"get-source-file":return typeof e.path=="string"&&n;case"execute":return n&&st(e.request)&&(e.request.mutationContext===void 0||se(e.request.mutationContext))&&(t.validateOperationRequest?.(e.request)??!0);case"undo":case"redo":return n&&e.mutationContext===void 0||n&&se(e.mutationContext)}}function it(e){if(e===void 0)return!0;if(!y(e)||typeof e.key!="string"||e.key.length===0)return!1;let t=e.instanceIndex,n=e.instanceCount;return t!==void 0&&(typeof t!="number"||!Number.isInteger(t)||t<0)||n!==void 0&&(typeof n!="number"||!Number.isInteger(n)||n<=0)||typeof t=="number"&&typeof n=="number"&&t>=n?!1:Object.keys(e).every(i=>i==="key"||i==="instanceIndex"||i==="instanceCount")}function st(e){return y(e)&&typeof e.id=="string"&&typeof e.siteId=="string"&&typeof e.baseSnapshotId=="string"&&L(e.composition)&&typeof e.kind=="string"&&y(e.target)&&(e.target.kind!=="route"||L(e.target.composition))&&typeof e.documentVersion=="number"&&Number.isInteger(e.documentVersion)&&e.documentVersion>=0&&y(e.params)}function L(e){return y(e)&&typeof e.routeId=="string"&&e.routeId.length>0&&(e.templateId===void 0||typeof e.templateId=="string"&&e.templateId.length>0)&&Object.keys(e).every(t=>t==="routeId"||t==="templateId")}function ot(e){return y(e)&&typeof e.routeId=="string"&&(e.effectiveTemplateId===void 0||typeof e.effectiveTemplateId=="string")}function ie(e){if(L(e.composition))return e.composition;throw new O(ue,"A composition selector is required for this request.")}function rt(e){if(y(e)&&L(e.composition))return e.composition;throw new O(ue,"A composition selector is required for execute.")}function ke(e){return{routeId:e.routeId,...e.effectiveTemplateId?{templateId:e.effectiveTemplateId}:{}}}function at(e){return e.activeComposition?N(e.activeComposition):null}function N(e){return JSON.stringify([e.routeId,e.effectiveTemplateId??null])}function H(e,t){return y(e)&&e.ok===!0?{...e,composition:t}:e}function ct(e,t){return!y(e)||e.ok!==!0?e:{...e,...t?{composition:t}:{},data:Te(e.data)}}function Te(e){let t=e;return Re(t.routeId?t:{...t,routeId:t.composition.routeId})}function y(e){return typeof e=="object"&&e!==null}function se(e){return y(e)&&typeof e.editingSessionId=="string"&&e.editingSessionId.length>0&&typeof e.lockId=="string"&&e.lockId.length>0&&typeof e.ownerId=="string"&&e.ownerId.length>0&&typeof e.leaseAssertion=="string"&&e.leaseAssertion.length>0}function oe(e){if(!(!y(e)||typeof e.code!="string"||e.code.length===0))return e.code}function re(e){return e instanceof Error||y(e)&&typeof e.message=="string"&&e.message.length>0?e.message:"Unknown websocket operation failure"}function ut(e){try{return v.extractRequestInfo(JSON.parse(e))}catch{return{id:"unknown",kind:"get-document"}}}var Y=class{constructor(){this.tail=Promise.resolve()}run(t){let n=this.tail.then(t,t);return this.tail=n.then(()=>{},()=>{}),n}};import{SiteEditOperationRequestSchema as wt,computeSiteEditCompositionKey as M}from"@vcp-dev/contracts";var xt="127.0.0.1",Ct=30218,vt="/__vcp/site-edit/bridge",De=6*1024*1024,bt=De*2,Rt=3e3,Pe=50,pe=".vcp/current-snapshot.json",Ae="__VCP_SITE_EDIT_BRIDGE_SERVERS__";function Be(e,t,n={}){let i=new le(Ue(t),e,!1,n);return i.start({listen:!1}),i}var le=class{constructor(t,n=dt.createServer((o,r)=>{r.writeHead(404),r.end("VCP site edit bridge server")}),i=!0,s={}){this.options=t,this.server=n,this.closeHttpServerOnStop=i,this.dependencies=s,this.runtime=null,this.activeHistorySessionId=null,this.historySessionTransition=Promise.resolve(),this.mutationQueue=new Y,this.eventListeners=new Set,this.routes=[],this.compositions=[],this.compositionFiles=[],this.compositionResolutionError=null,this.launchCandidateEntries=null,this.stopWatching=null,this.stopWebSocketServer=null,this.pendingChangedFiles=new Set,this.fileChangeTimer=null,this.isStarted=!1,this.stopping=!1,this.runtimeVersionFloors=new Map,this.activeHistoryStore=null,this.versionPersistence=Promise.resolve(),this.bridgeEngine=null,this.lastNotifiedHealth=null}start(t={}){if(!this.isStarted){this.stopping=!1;try{q.mkdirSync(b.join(this.options.projectRoot,".vcp"),{recursive:!0})}catch(n){console.warn(`[vcp-site-edit] failed to ensure .vcp directory: ${n instanceof Error?n.message:String(n)}`)}if(this.refreshCompositions(!0),this.isStarted=!0,this.createRuntime(),this.bridgeEngine=this.createBridgeEngine(),t.webSocket!==!1){let n=ye({server:this.server,path:this.options.path,sessionKey:this.options.sessionKey,host:this.options.host,allowedOrigins:this.options.allowedOrigins,engine:this.bridgeEngine});this.stopWebSocketServer=n.stop}this.stopWatching=new Et({projectRoot:this.options.projectRoot,watch_dirs:_t(this.options.runtime.watch_dirs),interval_ms:this.options.runtime.watch_interval_ms,debounce_ms:this.options.runtime.watch_debounce_ms??Pe,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(),t.listen!==!1&&this.server.listen(this.options.port,this.options.host),this.notifyHealthChanged()}}getEngine(){if(!this.bridgeEngine)throw new Error("VCP site edit preview bridge runtime is not ready");return this.bridgeEngine}getHealth(){let t=!!this.runtime&&!this.compositionResolutionError;return{ok:this.isStarted&&t,bridgePath:this.options.path,runtimeReady:t,routesIndexed:this.routes.length,sessionRequired:!!this.options.sessionKey}}stop(){this.stopping=!0,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 t=At(),n=Ht(this.options);t.get(n)===this&&t.delete(n),this.isStarted=!1,this.notifyHealthChanged()}notifyHealthChanged(){let t=this.options.onHealthChanged;if(!t)return;let n=this.getHealth(),i=JSON.stringify(n);if(i!==this.lastNotifiedHealth){this.lastNotifiedHealth=i;try{t(n)}catch(s){console.warn(`[vcp-site-edit] onHealthChanged callback failed: ${s instanceof Error?s.message:String(s)}`)}}}createRuntime(t,n=null){let i=this.runtime;this.activeHistoryStore=t??null;let s=(this.dependencies.createRuntime??ft)({...this.options.tenantId?{tenantId:this.options.tenantId}:{},siteId:this.options.siteId,snapshotId:this.options.snapshotId,projectRoot:this.options.projectRoot,compositions:this.compositions,onEvent:o=>{"version"in o&&typeof o.version=="number"&&this.recordRuntimeVersion(o.version,"composition"in o?o.composition:void 0);for(let r of this.eventListeners)r(o)},...t?{historyStore:t}:{},...this.getInitialDocumentVersions().length>0?{initialDocumentVersions:this.getInitialDocumentVersions()}:{}});this.runtime=s,this.activeHistorySessionId=n,i?.dispose(),this.notifyHealthChanged()}createBridgeEngine(){return{resolveComposition:t=>this.resolveComposition(t),initializeSession:t=>this.mutationQueue.run(async()=>{let n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)throw new Error(`${n.code}: ${n.message}`);let i=Tt(t.composition),s=this.getRuntime(),o=_(i);await s.initializeComposition(o);let c=s.getDocument(o).data;await this.recordRuntimeVersion(c.version,i);let p=(await s.getHistoryStatus()).data;return{ok:!0,composition:i,data:{document:c,historyStatus:p}}}),getDocument:async t=>{let n=this.getRuntime(),i=_(t);await n.initializeComposition(i);let s=n.getDocument(i);return await this.recordRuntimeVersion(s.data.version,t),{...s,composition:t}},getHistoryStatus:async t=>({...await this.getRuntime().getHistoryStatus(),composition:t}),getStyleContext:async t=>this.getRuntime().getStyleContext(_(t)),getObjectEditContext:async(t,n,i)=>this.getRuntime().getObjectEditContext(t,_(n),i),getClassNameSource:async(t,n)=>this.getRuntime().getClassNameSource(t,_(n)),getSourceTree:async t=>this.getRuntime().getSourceTree(_(t)),getSourceFile:async t=>this.getRuntime().getSourceFile({path:t.path,composition:_(t.composition)}),resolveSourceLocation:async t=>this.getRuntime().resolveSourceLocation({key:t.key,composition:_(t.composition)}),execute:(t,n)=>this.mutationQueue.run(async()=>{let i=await this.bindHistorySession(this.options.snapshotId);if(!i.ok)return de(i,t);let s=await this.getRuntime().executeOperation(t);return s.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(s.data.resultVersion,s.composition),s}),undo:t=>this.mutationQueue.run(async()=>{let n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)return de(n,void 0,t);let i=await this.getRuntime().undo();return i.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(i.data.resultVersion,i.composition??t),i.composition?i:{...i,composition:t}}),redo:t=>this.mutationQueue.run(async()=>{let n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)return de(n,void 0,t);let i=await this.getRuntime().redo();return i.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(i.data.resultVersion,i.composition??t),i.composition?i:{...i,composition:t}}),subscribe:t=>(this.eventListeners.add(t),()=>this.eventListeners.delete(t))}}async bindHistorySession(t){if(!this.options.historyRoot)return{ok:!1,code:"RECOVERY_PERSIST_FAILED",message:"Durable edit history is not configured."};if(this.activeHistorySessionId===t)return{ok:!0};let n=this.historySessionTransition.then(async()=>{if(this.activeHistorySessionId===t)return;let i=await(this.dependencies.openHistoryStore??gt)(Pt({root:this.options.historyRoot,siteId:this.options.siteId,snapshotId:this.options.snapshotId,editingSessionId:t}));if(!this.isStarted)return;let s=i.readDocumentVersion?await i.readDocumentVersion():0,o=this.compositions[0]?.context;if(o){let r=M(o);this.runtimeVersionFloors.set(r,Math.max(this.runtimeVersionFloors.get(r)??0,s))}this.createRuntime(i,t)});this.historySessionTransition=n.catch(()=>{});try{return await n,{ok:!0}}catch{return{ok:!1,code:"RECOVERY_PERSIST_FAILED",message:"Durable edit history could not be opened."}}}recordRuntimeVersion(t,n){let i=n?M(n):null;i&&this.runtimeVersionFloors.set(i,Math.max(this.runtimeVersionFloors.get(i)??0,t));let s=this.activeHistoryStore;if(!s?.writeDocumentVersion)return Promise.resolve();let o=i?this.runtimeVersionFloors.get(i)??t:t;return this.versionPersistence=this.versionPersistence.then(()=>s.writeDocumentVersion(o)).catch(()=>{}),this.versionPersistence}handleFileChanged(t){this.handleFilesChanged([t])}handleFilesChanged(t){for(let i of t)this.pendingChangedFiles.add(i);this.fileChangeTimer&&clearTimeout(this.fileChangeTimer);let n=this.options.runtime.watch_debounce_ms??Pe;this.fileChangeTimer=setTimeout(()=>{this.fileChangeTimer=null,this.flushChangedFiles()},n),this.fileChangeTimer?.unref?.()}flushChangedFiles(){if(this.fileChangeTimer&&(clearTimeout(this.fileChangeTimer),this.fileChangeTimer=null),this.pendingChangedFiles.size===0)return;let t=[...this.pendingChangedFiles].sort((n,i)=>n.localeCompare(i));if(this.pendingChangedFiles.clear(),t.some(Ft)&&this.scheduleSnapshotIdentityAdvance(),!!this.refreshCompositions(!1))for(let n of t)this.runtime?.notifyFileChanged(n)}scheduleSnapshotIdentityAdvance(){if(this.stopping||!this.isStarted)return;let t=this.readCurrentSnapshotMarker();!t||t===this.options.snapshotId||this.mutationQueue.run(()=>this.advanceSnapshotId(t)).catch(n=>{console.warn(`[vcp-site-edit] snapshot identity advance failed: ${n instanceof Error?n.message:String(n)}`)})}readCurrentSnapshotMarker(){try{let t=q.readFileSync(b.join(this.options.projectRoot,pe),"utf8"),n=JSON.parse(t),i=typeof n.snapshot_id=="string"?n.snapshot_id:"";return!i||fe(i)!==i?(console.warn("[vcp-site-edit] current-snapshot marker has no valid snapshot_id"),null):i}catch(t){return console.warn(`[vcp-site-edit] current-snapshot marker unreadable: ${t instanceof Error?t.message:String(t)}`),null}}async advanceSnapshotId(t){if(this.stopping||!this.isStarted||t===this.options.snapshotId)return;let n=this.options.snapshotId;this.options.snapshotId=t;try{if(this.options.historyRoot){let s=await this.bindHistorySession(t);if(!s.ok)throw new Error(`${s.code}: ${s.message}`)}else this.createRuntime()}catch(s){this.options.snapshotId=n,console.warn(`[vcp-site-edit] snapshot identity advance rolled back to ${n}: ${s instanceof Error?s.message:String(s)}`);return}let i=new Date().toISOString();for(let s of this.compositions){let o={type:"site-edit.snapshot.changed",siteId:this.options.siteId,composition:s.context,snapshotId:t,previousSnapshotId:n,at:i};for(let r of this.eventListeners)try{r(o)}catch(c){console.warn(`[vcp-site-edit] snapshot.changed listener failed: ${c instanceof Error?c.message:String(c)}`)}}try{this.options.onSnapshotIdChanged?.(t,n)}catch(s){console.warn(`[vcp-site-edit] onSnapshotIdChanged callback failed: ${s instanceof Error?s.message:String(s)}`)}}refreshCompositions(t=!1){try{let n=kt(this.options.projectRoot),i=It(n),s=i.length>0?i:(this.options.runtime.routes??[]).map(a=>({...a})),o=yt({files:n});if(o.length===0)throw new Error("No canonical App Router composition is indexed by the preview bridge.");let r=JSON.stringify(o.filter(a=>a.context.effectiveTemplateId!==void 0).map(a=>a.entryFile).sort());if(t&&(this.launchCandidateEntries=r),this.launchCandidateEntries!==r)throw new Error("SITE_EDIT_RUNTIME_RELOAD_REQUIRED: Candidate route collection changed since preview launch");let c=new Map(this.compositions.map(a=>[M(a.context),a])),p=new Map(o.map(a=>[M(a.context),a]));if(this.runtime){for(let[a,l]of c){let u=p.get(a);(!u||u.entryFile!==l.entryFile)&&this.runtime.unregisterComposition(_(l.context))}for(let[a,l]of p){let u=c.get(a);(!u||u.entryFile!==l.entryFile)&&this.runtime.registerComposition(l.context,l.entryFile)}}return this.routes=s,this.compositions=o,this.compositionFiles=n,this.compositionResolutionError=null,this.notifyHealthChanged(),!0}catch(n){let i=n instanceof Error?n:new Error(String(n));if(this.compositionResolutionError=i,t)throw i;return this.notifyHealthChanged(),!1}}resolveComposition(t){if(this.compositionResolutionError)throw this.compositionResolutionError;let n=St(t.routeId,this.routes,this.options.basePath);if(!n)throw new Error(`Route is not indexed by the preview bridge: ${t.routeId}`);let i=this.routes.find(r=>r.routeId===n);if(!i)throw new Error(`Route is not indexed by the preview bridge: ${t.routeId}`);let s=mt({selector:{routeId:n,...t.templateId!==void 0?{templateId:t.templateId}:{}},files:this.compositionFiles,canonicalEntryFile:i.entryFile}),o=M(s.context);if(!this.compositions.some(r=>M(r.context)===o))throw new Error(`Composition is not registered by the preview bridge: ${o}`);return s}getInitialDocumentVersions(){return this.compositions.flatMap(t=>{let n=this.runtimeVersionFloors.get(M(t.context));return n===void 0?[]:[{composition:t.context,version:n}]})}getRuntime(){if(!this.runtime)throw new Error("VCP site edit preview bridge runtime is not ready");return this.runtime}};function je(e){return Ue(e)}function Ue(e){return{tenantId:e.tenantId,siteId:e.siteId,snapshotId:e.snapshotId,projectRoot:b.resolve(e.projectRoot??process.cwd()),basePath:e.basePath??"",host:e.host??xt,port:e.port??Ct,path:e.path??vt,sessionKey:e.sessionKey??Ut(),historyRoot:e.historyRoot,allowedOrigins:e.allowedOrigins??[],runtime:e.runtime??{},onSnapshotIdChanged:e.onSnapshotIdChanged,onHealthChanged:e.onHealthChanged}}function _t(e){let t=["app","src/app","components/site","src/components/site","lib/generated","src/lib/generated","public"];return[...new Set([...e?.length?e:t,".vcp"])]}function kt(e){let t=[],n=["app","src/app",".vcp"],i=new Set([".git",".next",".turbo","coverage","dist","node_modules","output","snapshot-store"]),s=o=>{if(!q.existsSync(o))return;let r;try{r=q.readdirSync(o,{withFileTypes:!0})}catch{return}for(let c of r){if(c.name.startsWith(".")&&c.name!==".vcp")continue;if(c.isDirectory()){if(i.has(c.name))continue;s(b.join(o,c.name));continue}if(!c.isFile())continue;let p=b.join(o,c.name),a="";try{a=q.readFileSync(p,"utf8")}catch{}t.push({path:b.relative(e,p).replaceAll(b.sep,"/"),content:a})}};for(let o of n)s(b.join(e,o));return t.sort((o,r)=>o.path.localeCompare(r.path))}function Tt(e){if(!e||typeof e!="object"||typeof e.routeId!="string")throw new Error("Normalized composition context is required.");if("effectiveTemplateId"in e)return e;let t=e;return{routeId:t.routeId,...t.templateId?{effectiveTemplateId:t.templateId}:{}}}function _(e){return{routeId:e.routeId,...e.effectiveTemplateId?{templateId:e.effectiveTemplateId}:{}}}function Pt(e){return b.join(b.resolve(e.root),fe(e.siteId),fe(e.snapshotId),Oe("sha256").update(e.editingSessionId).digest("hex").slice(0,32))}function fe(e){return/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(e)&&e!=="."&&e!==".."?e:Oe("sha256").update(e).digest("hex").slice(0,32)}function At(){let e=globalThis;return e[Ae]??=new Map,e[Ae]}function Ht(e){return`${e.projectRoot}:${e.host}:${e.port}:${e.path}:${e.historyRoot??""}`}function de(e,t,n){let i=n??(t?.composition?{routeId:t.composition.routeId,...t.composition.templateId?{effectiveTemplateId:t.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:e.code,message:e.message},data:{requestId:t?.id??"mutation-context",kind:t?.kind??"update-text",composition:i,target:t?.target??{kind:"node",key:""},resultVersion:t?.documentVersion??0}}}function ye(e){let t=new lt({maxPayload:De,noServer:!0}),n=new WeakSet,i=o=>{new Q({socket:new ge(o),engine:e.engine,validateOperationRequest:r=>wt.safeParse(r).success})},s=(o,r,c)=>{if(!Nt(o,e))return;let p=Ot(o,e);if(!p){r.write(`HTTP/1.1 401 Unauthorized\r
1
+ import Re from"node:http";import{existsSync as F,readFileSync as U}from"node:fs";import{randomUUID as Zt}from"node:crypto";import{createRequire as Le}from"node:module";import{Socket as We}from"node:net";import z from"node:path";import{basename as qe,dirname as J,join as G}from"node:path";import{fileURLToPath as ze}from"node:url";import{createRequire as Kt}from"node:module";import{pathToFileURL as Wt}from"node:url";import{Worker as $t}from"node:worker_threads";var be=["resolveComposition","initializeSession","getDocument","getHistoryStatus","getStyleContext","getObjectEditContext","getClassNameSource","getSourceTree","getSourceFile","resolveSourceLocation","execute","getOperationResult","undo","redo"];function ne(e){let t=new Error(e.message);return t.name=e.name,e.code!==void 0&&(t.code=e.code),t}import dt from"node:http";import q from"node:fs";import{createHash as ye,randomBytes as ht,timingSafeEqual as pt}from"node:crypto";import b from"node:path";import{WebSocket as Me,WebSocketServer as lt}from"ws";import{createPreviewSiteEditEngineRuntime as ft,openFileHistoryStore as gt,resolveManagedPageTemplateComposition as mt,scanSiteEditCompositionsFromFiles as yt}from"@vcp-dev/site-edit-engine";import{resolveNextAppRouteId as St,scanNextAppRouterRoutesFromFiles as It}from"@vcp-dev/site-edit-engine/next-app-router";import{SiteEditSourceWatcher as wt}from"@vcp-dev/site-edit-engine/source-watcher";function _e(e){let t=new Map,n=[],i=new Map,s=[],o=e.pageComposition.status==="supported"?e.pageComposition.placementUnitKeys:[],r=new Map(o.map((d,f)=>[d,f])),c=e.pageComposition.status==="supported"?{status:"supported",containerKey:e.pageComposition.containerKey,hasBusinessMembers:e.pageComposition.hasBusinessMembers,placementUnitKeys:e.pageComposition.placementUnitKeys,placements:e.pageComposition.placements.map(d=>({placementKey:d.placementKey,placementUnitKey:d.placementUnitKey,relation:d.relation}))}:{status:"unsupported",reason:e.pageComposition.reason,diagnostics:e.pageComposition.diagnostics},p=e.entries.flatMap((d,f)=>d.dynamicDataSummary?[[f,d.dynamicDataSummary]]:[]),a=new Map(e.entries.map((d,f)=>[d.key,f])),l=[];for(let[d,f]of e.entries.entries()){let m=f.pageCompositionActionScope;if(!m)continue;if(m.kind!=="source-siblings"){l.push([d,{kind:m.kind}]);continue}let x=m.siblingKeys.map(w=>{let E=a.get(w);if(E===void 0)throw new Error("Render entry "+f.key+" references missing source sibling "+w);return E});l.push([d,{kind:"source-siblings",siblingEntryIndexes:x}])}let u=d=>{let f=t.get(d);if(typeof f=="number")return f;let m=n.length;return n.push(d),t.set(d,m),m},S=d=>{let f=null;for(let m of tt(d)){let x=`${f??"root"}\0${m}`,w=i.get(x);if(typeof w=="number"){f=w;continue}let E=s.length;s.push([f,u(m)]),i.set(x,E),f=E}if(f===null)throw new Error("Document key must not be empty");return f};return{encoding:"segment-trie-v1",siteId:e.siteId,snapshotId:e.snapshotId,composition:{...e.composition},routeId:e.composition.routeId,version:e.version,pageComposition:c,tokens:n,nodes:s,entries:e.entries.map(d=>{let f=d.pageCompositionUnitKey?r.get(d.pageCompositionUnitKey)??-1:-1;if(d.pageCompositionUnitKey&&f<0)throw new Error(`Render entry ${d.key} references unknown page composition unit ${d.pageCompositionUnitKey}`);return[S(d.key),et(d.operationSummary),...f>=0?[f]:[]]}),...l.length>0?{pageCompositionActionScopes:l}:{},...e.entries.every(d=>d.parentKey!==void 0)?{entryParentNodeIds:e.entries.map(d=>d.parentKey===null?null:S(d.parentKey))}:{},...p.length>0?{dynamicDataSummaries:p}:{}}}function et(e){return(e.canUpdateText?1:0)|(e.canInsertChild?2:0)|(e.canMove?4:0)|(e.canRemove?8:0)}function tt(e){if(!e)return[];let t=[],n=0,i=ve(e,n);if(i<0)return t.push(e),t;for(t.push(e.slice(0,i)),n=i;n<e.length;){if(i=ve(e,n+(e.startsWith("::",n)?2:1)),i<0){t.push(e.slice(n));break}t.push(e.slice(n,i)),n=i}return t}function ve(e,t){let n=e.indexOf("/",t),i=e.indexOf("::",t);return n<0?i:i<0?n:Math.min(n,i)}var ke="SITE_EDIT_COMPOSITION_SESSION_MISMATCH",ue="SITE_EDIT_COMPOSITION_SESSION_REQUIRED";var C=class e{constructor(){}static parseMessage(t,n={}){let i=JSON.parse(t);if(!e.isMessage(i,n))throw new Error("Invalid site edit bridge message");return i}static stringifyMessage(t){return JSON.stringify(t)}static extractRequestInfo(t){if(y(t)&&y(t.payload)){let n=typeof t.payload.id=="string"?t.payload.id:"unknown",i=this.isRequestKind(t.payload.kind)?t.payload.kind:"get-document";return{id:n,kind:i}}return{id:"unknown",kind:"get-document"}}static isRequestKind(t){return t==="initialize-session"||t==="get-document"||t==="get-history-status"||t==="get-style-context"||t==="get-object-edit-context"||t==="get-class-name-source"||t==="get-source-tree"||t==="get-source-file"||t==="resolve-source-location"||t==="execute"||t==="get-operation-result"||t==="undo"||t==="redo"}static isMessage(t,n={}){return!y(t)||typeof t.type!="string"?!1:t.type==="request"?nt(t.payload,n):t.type==="response"||t.type==="error"?y(t.payload)&&typeof t.payload.id=="string":t.type==="event"?y(t.payload)&&y(t.payload.event):t.type==="auth"?y(t.payload)&&typeof t.payload.key=="string":t.type==="auth-ok"&&y(t.payload)&&t.payload.ok===!0}},Q=class{constructor(t){this.options=t,this.session={subscribedCompositionKeys:new Set},this.messageQueue=new ce,this.eventDispatcher=new ae(n=>{this.sendJson(n)}),this.unsubscribe=t.engine.subscribe(n=>{this.handleEngineEvent(n)}),t.socket.onmessage=n=>{try{this.messageQueue.enqueue(()=>this.handleRawMessage(n.data))}catch(i){this.sendJson({type:"error",payload:{id:"unknown",kind:"get-document",message:i instanceof Error?i.message:"Bridge queue overflow"}}),t.socket.close(1013,"bridge busy")}},t.socket.onclose=()=>{this.unsubscribe(),this.session.activeComposition=void 0,this.session.subscribedCompositionKeys.clear()}}async handleMessage(t){try{let n=t;if(n.type!=="request")return;let i=n.payload,{id:s}=i;switch(i.kind){case"initialize-session":{let o=ie(i),r=await this.resolve(o),c=await this.options.engine.initializeSession({composition:r.context,...i.mutationContext?{mutationContext:i.mutationContext}:{}});this.activateSession(r.context),this.sendJson({type:"response",payload:{id:s,kind:i.kind,result:N({...c,data:{...c.data,document:Pe(c.data.document)}},r.context)}});return}case"get-document":{let o=await this.resolveWireContext(i),r=await this.options.engine.getDocument(o);this.sendResult(s,i.kind,ct(r,o));return}case"get-history-status":{let o=await this.resolveWireContext(i),r=await this.options.engine.getHistoryStatus(o);this.sendResult(s,i.kind,N(r,o));return}case"get-style-context":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,N(await this.options.engine.getStyleContext(o),o));return}case"get-object-edit-context":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,N(await this.options.engine.getObjectEditContext(i.key,o,i.selectionRef),o));return}case"get-class-name-source":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,N(await this.options.engine.getClassNameSource(i.key,o),o));return}case"get-source-tree":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,N(await this.options.engine.getSourceTree(o),o));return}case"get-source-file":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,N(await this.options.engine.getSourceFile({path:i.path,composition:o}),o));return}case"resolve-source-location":{let o=await this.resolveWireContext(i),r=N(await this.options.engine.resolveSourceLocation({key:i.key,composition:o}),o);this.sendResult(s,i.kind,r);return}case"execute":case"get-operation-result":{let o=await this.resolveOperationWireContext(i.request),r=await this.resolveWireContext(i);if(H(o)!==H(r))throw new O(ke,"The execute request composition does not match its operation composition.");let c=await this.normalizeOperationRequest(i.request,o);if(i.kind==="get-operation-result"){this.sendResult(s,i.kind,await this.options.engine.getOperationResult?.(c)??null);return}await this.handleBufferedOperation(s,i.kind,()=>this.options.engine.execute(c));return}case"undo":case"redo":{let o=await this.resolveWireContext(i);await this.handleBufferedOperation(s,i.kind,()=>i.kind==="undo"?this.options.engine.undo(o):this.options.engine.redo(o));return}}}catch(n){let i=C.extractRequestInfo(t);this.sendJson({type:"error",payload:{...i,message:re(n),code:oe(n)}})}}async resolve(t){return this.options.engine.resolveComposition(t)}async resolveAndAssert(t){let n=await this.resolve(t),i=this.session.activeComposition;if(!i)throw new O(ue,"Initialize a composition session before issuing this request.");if(H(i)!==H(n.context))throw new O(ke,"The request composition does not match the active socket session.");return n.context}async resolveWireContext(t){let n=ie(t);return this.resolveAndAssert(n)}async resolveOperationWireContext(t){let n=rt(t);return this.resolveAndAssert(n)}activateSession(t){this.session.activeComposition=t,this.session.subscribedCompositionKeys.clear(),this.session.subscribedCompositionKeys.add(H(t))}async normalizeOperationRequest(t,n){let i={...t,composition:Te(n)};if(i.target.kind==="route"){let s=i.target,o=ie(s),r=await this.resolveAndAssert(o);i.target={...s,composition:Te(r)}}return i}handleEngineEvent(t){let n=t?.composition;if(!ot(n))return;let i=H(n);this.session.subscribedCompositionKeys.has(i)&&(this.eventDispatcher.push(t),t.type==="site-edit.graph.invalidated"&&i===at(this.session)&&(this.session.activeComposition=void 0,this.session.subscribedCompositionKeys.delete(i)))}sendResult(t,n,i){this.sendJson({type:"response",payload:{id:t,kind:n,result:i}})}async handleRawMessage(t){try{await this.handleMessage(C.parseMessage(t,{validateOperationRequest:this.options.validateOperationRequest}))}catch(n){let i=ut(t);this.sendJson({type:"error",payload:{...i,message:re(n),code:oe(n)}})}}sendJson(t){this.options.socket.send(C.stringifyMessage(t))}async handleBufferedOperation(t,n,i){this.eventDispatcher.beginBuffering();try{let s=await i();this.sendResult(t,n,s)}catch(s){this.sendJson({type:"error",payload:{id:t,kind:n,message:re(s),code:oe(s)}})}finally{this.eventDispatcher.flush()}}},O=class extends Error{constructor(t,n){super(n),this.code=t,this.name="BridgeProtocolError"}},ae=class{constructor(t){this.send=t,this.bufferedEvents=null}push(t){let n={type:"event",payload:{event:t}};if(this.bufferedEvents){this.bufferedEvents.push(n);return}this.send(n)}beginBuffering(){this.bufferedEvents=[]}flush(){let t=this.bufferedEvents??[];this.bufferedEvents=null,t.forEach(n=>this.send(n))}},ce=class{constructor(t=64){this.maxQueued=t,this.queue=Promise.resolve(),this.queued=0}enqueue(t){if(this.queued>=this.maxQueued)throw new Error("Bridge request queue is full");this.queued+=1;let n=async()=>{this.queued-=1,await t()},i=this.queue.then(n,n);return this.queue=i.then(()=>{},()=>{}),i}};function nt(e,t){if(!y(e)||typeof e.id!="string"||!C.isRequestKind(e.kind))return!1;let n=L(e.composition);switch(e.kind){case"initialize-session":return n&&(e.mutationContext===void 0||se(e.mutationContext));case"get-document":case"get-style-context":return n;case"get-object-edit-context":return typeof e.key=="string"&&n&&it(e.selectionRef);case"get-class-name-source":case"resolve-source-location":return typeof e.key=="string"&&n;case"get-history-status":return n;case"get-source-tree":return n;case"get-source-file":return typeof e.path=="string"&&n;case"execute":case"get-operation-result":return n&&st(e.request)&&(e.request.mutationContext===void 0||se(e.request.mutationContext))&&(t.validateOperationRequest?.(e.request)??!0);case"undo":case"redo":return n&&e.mutationContext===void 0||n&&se(e.mutationContext)}}function it(e){if(e===void 0)return!0;if(!y(e)||typeof e.key!="string"||e.key.length===0)return!1;let t=e.instanceIndex,n=e.instanceCount;return t!==void 0&&(typeof t!="number"||!Number.isInteger(t)||t<0)||n!==void 0&&(typeof n!="number"||!Number.isInteger(n)||n<=0)||typeof t=="number"&&typeof n=="number"&&t>=n?!1:Object.keys(e).every(i=>i==="key"||i==="instanceIndex"||i==="instanceCount")}function st(e){return y(e)&&typeof e.id=="string"&&typeof e.siteId=="string"&&typeof e.baseSnapshotId=="string"&&L(e.composition)&&typeof e.kind=="string"&&y(e.target)&&(e.target.kind!=="route"||L(e.target.composition))&&typeof e.documentVersion=="number"&&Number.isInteger(e.documentVersion)&&e.documentVersion>=0&&y(e.params)}function L(e){return y(e)&&typeof e.routeId=="string"&&e.routeId.length>0&&(e.templateId===void 0||typeof e.templateId=="string"&&e.templateId.length>0)&&Object.keys(e).every(t=>t==="routeId"||t==="templateId")}function ot(e){return y(e)&&typeof e.routeId=="string"&&(e.effectiveTemplateId===void 0||typeof e.effectiveTemplateId=="string")}function ie(e){if(L(e.composition))return e.composition;throw new O(ue,"A composition selector is required for this request.")}function rt(e){if(y(e)&&L(e.composition))return e.composition;throw new O(ue,"A composition selector is required for execute.")}function Te(e){return{routeId:e.routeId,...e.effectiveTemplateId?{templateId:e.effectiveTemplateId}:{}}}function at(e){return e.activeComposition?H(e.activeComposition):null}function H(e){return JSON.stringify([e.routeId,e.effectiveTemplateId??null])}function N(e,t){return y(e)&&e.ok===!0?{...e,composition:t}:e}function ct(e,t){return!y(e)||e.ok!==!0?e:{...e,...t?{composition:t}:{},data:Pe(e.data)}}function Pe(e){let t=e;return _e(t.routeId?t:{...t,routeId:t.composition.routeId})}function y(e){return typeof e=="object"&&e!==null}function se(e){return y(e)&&typeof e.editingSessionId=="string"&&e.editingSessionId.length>0&&typeof e.lockId=="string"&&e.lockId.length>0&&typeof e.ownerId=="string"&&e.ownerId.length>0&&typeof e.leaseAssertion=="string"&&e.leaseAssertion.length>0}function oe(e){if(!(!y(e)||typeof e.code!="string"||e.code.length===0))return e.code}function re(e){return e instanceof Error||y(e)&&typeof e.message=="string"&&e.message.length>0?e.message:"Unknown websocket operation failure"}function ut(e){try{return C.extractRequestInfo(JSON.parse(e))}catch{return{id:"unknown",kind:"get-document"}}}var Y=class{constructor(){this.tail=Promise.resolve()}run(t){let n=this.tail.then(t,t);return this.tail=n.then(()=>{},()=>{}),n}};import{SiteEditOperationRequestSchema as Et,computeSiteEditCompositionKey as M}from"@vcp-dev/contracts";var xt="127.0.0.1",Rt=30218,Ct="/__vcp/site-edit/bridge",De=6*1024*1024,bt=De*2,vt=3e3,Ae=50,pe=".vcp/current-snapshot.json",Ne="__VCP_SITE_EDIT_BRIDGE_SERVERS__";function Be(e,t,n={}){let i=new le(Ue(t),e,!1,n);return i.start({listen:!1}),i}var le=class{constructor(t,n=dt.createServer((o,r)=>{r.writeHead(404),r.end("VCP site edit bridge server")}),i=!0,s={}){this.options=t,this.server=n,this.closeHttpServerOnStop=i,this.dependencies=s,this.runtime=null,this.activeHistorySessionId=null,this.historySessionTransition=Promise.resolve(),this.mutationQueue=new Y,this.operationReceipts=new Map,this.eventListeners=new Set,this.routes=[],this.compositions=[],this.compositionFiles=[],this.compositionResolutionError=null,this.launchCandidateEntries=null,this.stopWatching=null,this.stopWebSocketServer=null,this.pendingChangedFiles=new Set,this.fileChangeTimer=null,this.isStarted=!1,this.stopping=!1,this.runtimeVersionFloors=new Map,this.activeHistoryStore=null,this.versionPersistence=Promise.resolve(),this.bridgeEngine=null,this.lastNotifiedHealth=null}start(t={}){if(!this.isStarted){this.stopping=!1;try{q.mkdirSync(b.join(this.options.projectRoot,".vcp"),{recursive:!0})}catch(n){console.warn(`[vcp-site-edit] failed to ensure .vcp directory: ${n instanceof Error?n.message:String(n)}`)}if(this.refreshCompositions(!0),this.isStarted=!0,this.createRuntime(),this.bridgeEngine=this.createBridgeEngine(),t.webSocket!==!1){let n=Se({server:this.server,path:this.options.path,sessionKey:this.options.sessionKey,host:this.options.host,allowedOrigins:this.options.allowedOrigins,engine:this.bridgeEngine});this.stopWebSocketServer=n.stop}this.stopWatching=new wt({projectRoot:this.options.projectRoot,watch_dirs:_t(this.options.runtime.watch_dirs),interval_ms:this.options.runtime.watch_interval_ms,debounce_ms:this.options.runtime.watch_debounce_ms??Ae,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(),t.listen!==!1&&this.server.listen(this.options.port,this.options.host),this.notifyHealthChanged()}}getEngine(){if(!this.bridgeEngine)throw new Error("VCP site edit preview bridge runtime is not ready");return this.bridgeEngine}getHealth(){let t=!!this.runtime&&!this.compositionResolutionError;return{ok:this.isStarted&&t,bridgePath:this.options.path,runtimeReady:t,routesIndexed:this.routes.length,sessionRequired:!!this.options.sessionKey}}stop(){this.stopping=!0,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 t=At(),n=Nt(this.options);t.get(n)===this&&t.delete(n),this.isStarted=!1,this.notifyHealthChanged()}notifyHealthChanged(){let t=this.options.onHealthChanged;if(!t)return;let n=this.getHealth(),i=JSON.stringify(n);if(i!==this.lastNotifiedHealth){this.lastNotifiedHealth=i;try{t(n)}catch(s){console.warn(`[vcp-site-edit] onHealthChanged callback failed: ${s instanceof Error?s.message:String(s)}`)}}}createRuntime(t,n=null){let i=this.runtime;this.activeHistoryStore=t??null;let s=(this.dependencies.createRuntime??ft)({...this.options.tenantId?{tenantId:this.options.tenantId}:{},siteId:this.options.siteId,snapshotId:this.options.snapshotId,projectRoot:this.options.projectRoot,compositions:this.compositions,onEvent:o=>{"version"in o&&typeof o.version=="number"&&this.recordRuntimeVersion(o.version,"composition"in o?o.composition:void 0);for(let r of this.eventListeners)r(o)},...t?{historyStore:t}:{},...this.getInitialDocumentVersions().length>0?{initialDocumentVersions:this.getInitialDocumentVersions()}:{}});this.runtime=s,this.activeHistorySessionId=n,i?.dispose(),this.notifyHealthChanged()}createBridgeEngine(){return{resolveComposition:t=>this.resolveComposition(t),initializeSession:t=>this.mutationQueue.run(async()=>{let n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)throw new Error(`${n.code}: ${n.message}`);let i=Tt(t.composition),s=this.getRuntime(),o=_(i);await s.initializeComposition(o);let c=s.getDocument(o).data;await this.recordRuntimeVersion(c.version,i);let p=(await s.getHistoryStatus()).data;return{ok:!0,composition:i,data:{document:c,historyStatus:p}}}),getDocument:async t=>{let n=this.getRuntime(),i=_(t);await n.initializeComposition(i);let s=n.getDocument(i);return await this.recordRuntimeVersion(s.data.version,t),{...s,composition:t}},getHistoryStatus:async t=>({...await this.getRuntime().getHistoryStatus(),composition:t}),getStyleContext:async t=>this.getRuntime().getStyleContext(_(t)),getObjectEditContext:async(t,n,i)=>this.getRuntime().getObjectEditContext(t,_(n),i),getClassNameSource:async(t,n)=>this.getRuntime().getClassNameSource(t,_(n)),getSourceTree:async t=>this.getRuntime().getSourceTree(_(t)),getSourceFile:async t=>this.getRuntime().getSourceFile({path:t.path,composition:_(t.composition)}),resolveSourceLocation:async t=>this.getRuntime().resolveSourceLocation({key:t.key,composition:_(t.composition)}),execute:(t,n)=>this.executeWithReceipt(t,()=>this.mutationQueue.run(async()=>{let i=await this.bindHistorySession(this.options.snapshotId);if(!i.ok)return de(i,t);let s=await this.getRuntime().executeOperation(t);return s.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(s.data.resultVersion,s.composition),s})),getOperationResult:t=>{if(t.siteId!==this.options.siteId||t.baseSnapshotId!==this.options.snapshotId)return null;let n=this.operationReceipts.get(this.operationReceiptKey(t));return n?.fingerprint===this.operationFingerprint(t)?n.result:null},undo:t=>this.mutationQueue.run(async()=>{let n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)return de(n,void 0,t);let i=await this.getRuntime().undo();return i.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(i.data.resultVersion,i.composition??t),i.composition?i:{...i,composition:t}}),redo:t=>this.mutationQueue.run(async()=>{let n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)return de(n,void 0,t);let i=await this.getRuntime().redo();return i.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(i.data.resultVersion,i.composition??t),i.composition?i:{...i,composition:t}}),subscribe:t=>(this.eventListeners.add(t),()=>this.eventListeners.delete(t))}}operationReceiptKey(t){return JSON.stringify([t.siteId,t.baseSnapshotId,t.id])}operationFingerprint(t){return ye("sha256").update(JSON.stringify(t)).digest("hex")}executeWithReceipt(t,n){if(t.siteId!==this.options.siteId||t.baseSnapshotId!==this.options.snapshotId)return n();let i=this.operationReceiptKey(t),s=this.operationFingerprint(t),o=this.operationReceipts.get(i);if(o)return o.fingerprint!==s?Promise.reject(new Error("Operation ID was reused with a different request.")):o.result;let r={fingerprint:s,result:n(),settled:!1};return this.operationReceipts.set(i,r),r.result.then(()=>{r.settled=!0;for(let[c,p]of this.operationReceipts){if(this.operationReceipts.size<=256)break;p.settled&&this.operationReceipts.delete(c)}},()=>{this.operationReceipts.delete(i)}),r.result}async bindHistorySession(t){if(!this.options.historyRoot)return{ok:!1,code:"RECOVERY_PERSIST_FAILED",message:"Durable edit history is not configured."};if(this.activeHistorySessionId===t)return{ok:!0};let n=this.historySessionTransition.then(async()=>{if(this.activeHistorySessionId===t)return;let i=await(this.dependencies.openHistoryStore??gt)(Pt({root:this.options.historyRoot,siteId:this.options.siteId,snapshotId:this.options.snapshotId,editingSessionId:t}));if(!this.isStarted)return;let s=i.readDocumentVersion?await i.readDocumentVersion():0,o=this.compositions[0]?.context;if(o){let r=M(o);this.runtimeVersionFloors.set(r,Math.max(this.runtimeVersionFloors.get(r)??0,s))}this.createRuntime(i,t)});this.historySessionTransition=n.catch(()=>{});try{return await n,{ok:!0}}catch{return{ok:!1,code:"RECOVERY_PERSIST_FAILED",message:"Durable edit history could not be opened."}}}recordRuntimeVersion(t,n){let i=n?M(n):null;i&&this.runtimeVersionFloors.set(i,Math.max(this.runtimeVersionFloors.get(i)??0,t));let s=this.activeHistoryStore;if(!s?.writeDocumentVersion)return Promise.resolve();let o=i?this.runtimeVersionFloors.get(i)??t:t;return this.versionPersistence=this.versionPersistence.then(()=>s.writeDocumentVersion(o)).catch(()=>{}),this.versionPersistence}handleFileChanged(t){this.handleFilesChanged([t])}handleFilesChanged(t){for(let i of t)this.pendingChangedFiles.add(i);this.fileChangeTimer&&clearTimeout(this.fileChangeTimer);let n=this.options.runtime.watch_debounce_ms??Ae;this.fileChangeTimer=setTimeout(()=>{this.fileChangeTimer=null,this.flushChangedFiles()},n),this.fileChangeTimer?.unref?.()}flushChangedFiles(){if(this.fileChangeTimer&&(clearTimeout(this.fileChangeTimer),this.fileChangeTimer=null),this.pendingChangedFiles.size===0)return;let t=[...this.pendingChangedFiles].sort((n,i)=>n.localeCompare(i));if(this.pendingChangedFiles.clear(),t.some(Ft)&&this.scheduleSnapshotIdentityAdvance(),!!this.refreshCompositions(!1))for(let n of t)this.runtime?.notifyFileChanged(n)}scheduleSnapshotIdentityAdvance(){if(this.stopping||!this.isStarted)return;let t=this.readCurrentSnapshotMarker();!t||t===this.options.snapshotId||this.mutationQueue.run(()=>this.advanceSnapshotId(t)).catch(n=>{console.warn(`[vcp-site-edit] snapshot identity advance failed: ${n instanceof Error?n.message:String(n)}`)})}readCurrentSnapshotMarker(){try{let t=q.readFileSync(b.join(this.options.projectRoot,pe),"utf8"),n=JSON.parse(t),i=typeof n.snapshot_id=="string"?n.snapshot_id:"";return!i||fe(i)!==i?(console.warn("[vcp-site-edit] current-snapshot marker has no valid snapshot_id"),null):i}catch(t){return console.warn(`[vcp-site-edit] current-snapshot marker unreadable: ${t instanceof Error?t.message:String(t)}`),null}}async advanceSnapshotId(t){if(this.stopping||!this.isStarted||t===this.options.snapshotId)return;let n=this.options.snapshotId;this.options.snapshotId=t;try{if(this.options.historyRoot){let s=await this.bindHistorySession(t);if(!s.ok)throw new Error(`${s.code}: ${s.message}`)}else this.createRuntime()}catch(s){this.options.snapshotId=n,console.warn(`[vcp-site-edit] snapshot identity advance rolled back to ${n}: ${s instanceof Error?s.message:String(s)}`);return}let i=new Date().toISOString();for(let s of this.compositions){let o={type:"site-edit.snapshot.changed",siteId:this.options.siteId,composition:s.context,snapshotId:t,previousSnapshotId:n,at:i};for(let r of this.eventListeners)try{r(o)}catch(c){console.warn(`[vcp-site-edit] snapshot.changed listener failed: ${c instanceof Error?c.message:String(c)}`)}}try{this.options.onSnapshotIdChanged?.(t,n)}catch(s){console.warn(`[vcp-site-edit] onSnapshotIdChanged callback failed: ${s instanceof Error?s.message:String(s)}`)}}refreshCompositions(t=!1){try{let n=kt(this.options.projectRoot),i=It(n),s=i.length>0?i:(this.options.runtime.routes??[]).map(a=>({...a})),o=yt({files:n});if(o.length===0)throw new Error("No canonical App Router composition is indexed by the preview bridge.");let r=JSON.stringify(o.filter(a=>a.context.effectiveTemplateId!==void 0).map(a=>a.entryFile).sort());if(t&&(this.launchCandidateEntries=r),this.launchCandidateEntries!==r)throw new Error("SITE_EDIT_RUNTIME_RELOAD_REQUIRED: Candidate route collection changed since preview launch");let c=new Map(this.compositions.map(a=>[M(a.context),a])),p=new Map(o.map(a=>[M(a.context),a]));if(this.runtime){for(let[a,l]of c){let u=p.get(a);(!u||u.entryFile!==l.entryFile)&&this.runtime.unregisterComposition(_(l.context))}for(let[a,l]of p){let u=c.get(a);(!u||u.entryFile!==l.entryFile)&&this.runtime.registerComposition(l.context,l.entryFile)}}return this.routes=s,this.compositions=o,this.compositionFiles=n,this.compositionResolutionError=null,this.notifyHealthChanged(),!0}catch(n){let i=n instanceof Error?n:new Error(String(n));if(this.compositionResolutionError=i,t)throw i;return this.notifyHealthChanged(),!1}}resolveComposition(t){if(this.compositionResolutionError)throw this.compositionResolutionError;let n=St(t.routeId,this.routes,this.options.basePath);if(!n)throw new Error(`Route is not indexed by the preview bridge: ${t.routeId}`);let i=this.routes.find(r=>r.routeId===n);if(!i)throw new Error(`Route is not indexed by the preview bridge: ${t.routeId}`);let s=mt({selector:{routeId:n,...t.templateId!==void 0?{templateId:t.templateId}:{}},files:this.compositionFiles,canonicalEntryFile:i.entryFile}),o=M(s.context);if(!this.compositions.some(r=>M(r.context)===o))throw new Error(`Composition is not registered by the preview bridge: ${o}`);return s}getInitialDocumentVersions(){return this.compositions.flatMap(t=>{let n=this.runtimeVersionFloors.get(M(t.context));return n===void 0?[]:[{composition:t.context,version:n}]})}getRuntime(){if(!this.runtime)throw new Error("VCP site edit preview bridge runtime is not ready");return this.runtime}};function je(e){return Ue(e)}function Ue(e){return{tenantId:e.tenantId,siteId:e.siteId,snapshotId:e.snapshotId,projectRoot:b.resolve(e.projectRoot??process.cwd()),basePath:e.basePath??"",host:e.host??xt,port:e.port??Rt,path:e.path??Ct,sessionKey:e.sessionKey??Ut(),historyRoot:e.historyRoot,allowedOrigins:e.allowedOrigins??[],runtime:e.runtime??{},onSnapshotIdChanged:e.onSnapshotIdChanged,onHealthChanged:e.onHealthChanged}}function _t(e){let t=["app","src/app","components/site","src/components/site","lib/generated","src/lib/generated","public"];return[...new Set([...e?.length?e:t,".vcp"])]}function kt(e){let t=[],n=["app","src/app",".vcp"],i=new Set([".git",".next",".turbo","coverage","dist","node_modules","output","snapshot-store"]),s=o=>{if(!q.existsSync(o))return;let r;try{r=q.readdirSync(o,{withFileTypes:!0})}catch{return}for(let c of r){if(c.name.startsWith(".")&&c.name!==".vcp")continue;if(c.isDirectory()){if(i.has(c.name))continue;s(b.join(o,c.name));continue}if(!c.isFile())continue;let p=b.join(o,c.name),a="";try{a=q.readFileSync(p,"utf8")}catch{}t.push({path:b.relative(e,p).replaceAll(b.sep,"/"),content:a})}};for(let o of n)s(b.join(e,o));return t.sort((o,r)=>o.path.localeCompare(r.path))}function Tt(e){if(!e||typeof e!="object"||typeof e.routeId!="string")throw new Error("Normalized composition context is required.");if("effectiveTemplateId"in e)return e;let t=e;return{routeId:t.routeId,...t.templateId?{effectiveTemplateId:t.templateId}:{}}}function _(e){return{routeId:e.routeId,...e.effectiveTemplateId?{templateId:e.effectiveTemplateId}:{}}}function Pt(e){return b.join(b.resolve(e.root),fe(e.siteId),fe(e.snapshotId),ye("sha256").update(e.editingSessionId).digest("hex").slice(0,32))}function fe(e){return/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(e)&&e!=="."&&e!==".."?e:ye("sha256").update(e).digest("hex").slice(0,32)}function At(){let e=globalThis;return e[Ne]??=new Map,e[Ne]}function Nt(e){return`${e.projectRoot}:${e.host}:${e.port}:${e.path}:${e.historyRoot??""}`}function de(e,t,n){let i=n??(t?.composition?{routeId:t.composition.routeId,...t.composition.templateId?{effectiveTemplateId:t.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:e.code,message:e.message},data:{requestId:t?.id??"mutation-context",kind:t?.kind??"update-text",composition:i,target:t?.target??{kind:"node",key:""},resultVersion:t?.documentVersion??0}}}function Se(e){let t=new lt({maxPayload:De,noServer:!0}),n=new WeakSet,i=o=>{new Q({socket:new ge(o),engine:e.engine,validateOperationRequest:r=>Et.safeParse(r).success})},s=(o,r,c)=>{if(!Ht(o,e))return;let p=Ot(o,e);if(!p){r.write(`HTTP/1.1 401 Unauthorized\r
2
2
  Connection: close\r
3
3
  \r
4
- `),r.destroy();return}p.authenticatedByHeader&&n.add(o),t.handleUpgrade(o,r,c,a=>{t.emit("connection",a,o)})};return e.server.on("upgrade",s),t.on("connection",(o,r)=>{if(n.has(r)){i(o);return}Mt(o,e.sessionKey,()=>{i(o)})}),t.stop=()=>{e.server.off("upgrade",s);for(let o of t.clients)o.close(1001,"bridge stopped");t.close()},t}var ge=class{constructor(t){this.socket=t,this.onmessage=null,this.onclose=null,t.on("error",()=>{}),t.on("message",n=>{this.onmessage?.({data:n.toString()})}),t.on("close",()=>{this.onclose?.()})}send(t){if(this.socket.readyState===Me.OPEN){if(this.socket.bufferedAmount+Buffer.byteLength(t,"utf8")>bt){this.socket.close(1013,"bridge backpressure");return}this.socket.send(t)}}close(t,n){this.socket.close(t,n)}};function Nt(e,t){return new URL(e.url??"/","http://localhost").pathname===t.path}function Ot(e,t){if(new URL(e.url??"/","http://localhost").searchParams.has("vcp_bridge_key"))return null;let i=he(e.headers["x-vcp-site-edit-key"]),s=Fe(i,t.sessionKey),o=he(e.headers.host),r=he(e.headers.origin);return o&&!Dt(o,t.host,r)?null:r?jt(r,o,t.allowedOrigins)?{authenticatedByHeader:s}:null:s?{authenticatedByHeader:!0}:null}function Mt(e,t,n){let i=setTimeout(()=>{e.close(1008,"bridge authentication timeout")},Rt),s,o=()=>{clearTimeout(i),e.off("message",s),e.off("close",o)},r=()=>{o(),e.close(1008,"bridge authentication failed")};s=c=>{try{let p=v.parseMessage(c.toString());if(p.type!=="auth"||!Fe(p.payload.key,t)){r();return}o(),e.readyState===Me.OPEN&&e.send(v.stringifyMessage({type:"auth-ok",payload:{ok:!0}})),n()}catch{r()}},e.on("message",s),e.on("close",o)}function Fe(e,t){if(!e)return!1;let n=Buffer.from(e),i=Buffer.from(t);return n.length===i.length&&pt(n,i)}function Dt(e,t,n){let i=Ne(e),s=Ne(t);return i===s||He(s)&&He(i)&&(!n||me(n,e))||Bt(s)&&(!n||me(n,e))}function Bt(e){return e==="0.0.0.0"||e==="::"}function He(e){return e==="localhost"||e==="127.0.0.1"||e==="::1"}function jt(e,t,n){return n.includes(e)||(t?me(e,t):!1)}function me(e,t){try{return new URL(e).host===Ke(t)}catch{return!1}}function Ne(e){let t=Ke(e);return t.startsWith("[")?t.slice(1,t.indexOf("]")):t.split(":").length-1===1?t.split(":",1)[0]??"":t}function Ke(e){return e.trim().toLowerCase()}function he(e){return Array.isArray(e)?e[0]:e}function Ut(){return ht(32).toString("base64url")}function Ft(e){let t=e.replaceAll("\\","/");return t===pe||t.endsWith(`/${pe}`)}var Vt="SITE_EDIT_ENGINE_UNAVAILABLE",Lt=5e3,qt=1024,zt="VCP_SITE_EDIT_ENGINE_MAX_HEAP_MB",Jt=3,Gt=10*6e4,Qt=1012;function Se(e,t,n={}){let i=je(t),{onSnapshotIdChanged:s,onHealthChanged:o,...r}=i,c={options:r},p=n.maxHeapMb??Xt(process.env[zt])??qt,a=n.maxRestarts??Jt,l=n.restartWindowMs??Gt,u="starting",S,d=0,f=[],m=null,x=0,E=new Map,w=new Set,K,D,W=new Promise((h,g)=>{K=h,D=g});W.catch(()=>{});let C=h=>{let g=new Error(`VCP site edit preview bridge runtime is not ready: ${h}`);return g.code=Vt,g},$=h=>{for(let g of E.values())g.reject(h);E.clear()},k=h=>{switch(h.type){case"ready":m=h.health,u==="starting"?(u="ready",K()):u==="restarting"&&(u="ready",console.warn("[vcp-site-edit] engine worker restarted"));return;case"start-failed":u==="starting"&&T(ne(h.error));return;case"result":{let g=E.get(h.id);if(!g)return;E.delete(h.id),h.ok?g.resolve(h.value):g.reject(ne(h.error));return}case"event":for(let g of w)try{g(h.event)}catch(I){console.warn(`[vcp-site-edit] engine event listener failed: ${I instanceof Error?I.message:String(I)}`)}return;case"health":m=h.health;return;case"snapshot-id-changed":c.options.snapshotId=h.next;try{s?.(h.next,h.previous)}catch(g){console.warn(`[vcp-site-edit] onSnapshotIdChanged callback failed: ${g instanceof Error?g.message:String(g)}`)}return}},B=()=>{let h=d+=1,g=n.workerUrl??new URL("./engine-worker.js",import.meta.url),I=new $t(Yt(g),{workerData:c,resourceLimits:{maxOldGenerationSizeMb:p},...n.execArgv?{execArgv:n.execArgv}:{}});I.unref();let A=()=>h===d;I.on("message",R=>{A()&&k(R)}),I.on("error",R=>{A()&&T(R instanceof Error?R:new Error(String(R)))}),I.on("exit",R=>{A()&&T(new Error(`engine worker exited with code ${R}`))}),S=I,n.onWorker?.(I)},T=h=>{if(u==="stopped"||u==="failed")return;if($(C(h.message)),m=null,u==="starting"){u="failed",console.error(`[vcp-site-edit] engine worker failed to start: ${h.message}`),D(h);return}let g=Date.now();for(;f.length>0&&g-f[0]>l;)f.shift();if(f.length>=a){u="failed",console.error(`[vcp-site-edit] engine worker stopped unexpectedly and exhausted ${a} restarts: ${h.message}`);return}f.push(g),u="restarting";for(let I of P.clients)I.close(Qt,"site edit engine restarting");console.error(`[vcp-site-edit] engine worker stopped unexpectedly, restarting (${f.length}/${a}): ${h.message}`),B()},V=(h,g)=>{if(u==="failed"||u==="stopped"||u==="restarting")return Promise.reject(C(u));let I=x+=1;return new Promise((A,R)=>{E.set(I,{resolve:A,reject:R});let Ze={type:"call",id:I,method:h,args:g};S.postMessage(Ze)})},j=Object.fromEntries(ve.map(h=>[h,(...g)=>V(h,g)])),P=ye({server:e,path:i.path,sessionKey:i.sessionKey,host:i.host,allowedOrigins:i.allowedOrigins,engine:{...j,subscribe(h){return w.add(h),()=>w.delete(h)}}});return B(),{getHealth(){return u==="ready"&&m?m:{ok:!1,bridgePath:i.path,runtimeReady:!1,routesIndexed:m?.routesIndexed??0,sessionRequired:!!i.sessionKey}},stop(){if(u==="stopped")return;let h=u==="starting";u="stopped",P.stop(),h&&D(C("bridge stopped")),$(C("bridge stopped")),w.clear();let g=S,I={type:"stop"};g.postMessage(I);let A=setTimeout(()=>{g.terminate()},Lt);A.unref(),g.once("exit",()=>clearTimeout(A))},whenReady(){return W},eventListeners:w}}function Yt(e){if(!e.pathname.endsWith(".ts"))return e;let t=Wt(Kt(import.meta.url).resolve("tsx/esm/api")).href,n=[`import { tsImport } from ${JSON.stringify(t)};`,`await tsImport(${JSON.stringify(e.href)}, ${JSON.stringify(e.href)});`].join(`
5
- `);return new URL(`data:text/javascript,${encodeURIComponent(n)}`)}function Xt(e){if(!e||!/^\d+$/.test(e.trim()))return;let t=Number(e.trim());return Number.isSafeInteger(t)&&t>0?t:void 0}var en="next",tn="VCP_SITE_EDIT_ENGINE_IN_PROCESS",Je="127.0.0.1",nn=3e3,ee="/__vcp/site-edit/bridge",Ge="/__vcp/site-edit/health",sn="probe",on="render",$e="/_error",te="/__vcp/site-edit/client/",rn=`${te}auto-bootstrap.js`,Qe='data-vcp-site-edit-bootstrap="true"',an=["next.config.ts","next.config.mts","next.config.cts","next.config.js","next.config.mjs","next.config.cjs"],cn="@vcp-dev/site-edit-engine/webpack-loader",un=/@vcp\/site-edit-engine\/(?:webpack-loader|site-edit-instrumentation-loader)/,dn=[/\bconfig\.webpack\s*=/,/\bwebpack\s*\([^)]*\)\s*\{/,/\bwebpack\s*:\s*(?:async\s*)?(?:\([^)]*\)|[A-Za-z_$][\w$]*)?\s*=>/,/\bwebpack\s*:\s*(?:async\s+)?function\b/],hn=new Set(["auto-bootstrap.js","client.js","composition-key.js","designer-trace.js","document-codec.js","property-preview.js","protocol.js","window-message.js"]);async function Pi(e={},t={}){let n=t.process??process,i=t.createServer??xe.createServer,s=t.attachBridgeServer??(n.env[tn]==="1"?Be:Se),o=t.loadNext??Wn,r=z.resolve(e.projectRoot??process.cwd()),c=e.host??Je,p=e.port??qn(n.env.PORT)??nn,a=e.bridgePath??ee,l=Sn(a),u=Bn(),S=e.basePath??n.env.VCP_SITE_PREVIEW_BASE_PATH??"/",d=(e.tenantId??n.env.VCP_TENANT_ID)?.trim()||void 0,f=await o(r),m=pn(r),x=f({dev:!0,dir:r,hostname:c,port:p,...ln(m)}),E=x.getRequestHandler(),w=e.siteId??n.env.VCP_SITE_ID??"018f6f4d-a9b8-7120-8000-000000000120",K=e.snapshotId??n.env.VCP_SNAPSHOT_ID??Ln(r),D=e.historyRoot??n.env.VCP_SITE_EDIT_HISTORY_ROOT,W=D?.trim()?z.resolve(D):void 0,C=null,$={launchId:Zt(),pid:process.pid,snapshotId:K},k=i((P,h)=>{bn({basePath:S,bridgePath:a,bridgeHealthPath:l,bridgeSessionKey:u,getBridgeHealth:()=>C?.getHealth()??An(a),launch:$,runRenderProbe:()=>kn(x),handle:E,request:P,response:h}).catch(g=>{console.error(g),h.headersSent||(h.statusCode=500),h.end("site edit preview request failed")})}),B=null,T=null,V=()=>T||(Z(()=>n.off("SIGINT",j)),Z(()=>n.off("SIGTERM",j)),Z(()=>B?.()),B=null,Z(()=>C?.stop()),C=null,T=Promise.allSettled([Jn(k),Gn(()=>x.close())]).then(()=>{}),T),j=()=>{V()};try{return await x.prepare(),C=s(k,{...d?{tenantId:d}:{},siteId:w,snapshotId:K,projectRoot:r,basePath:S,host:c,port:p,path:a,sessionKey:u,...W?{historyRoot:W}:{},onSnapshotIdChanged:P=>{$.snapshotId=P}}),B=mn({server:k,bridgePath:a,handleUpgrade:x.getUpgradeHandler()}),n.on("SIGINT",j),n.on("SIGTERM",j),await C.whenReady?.(),await zn(k,p,c),{bundler:m,close:V,host:c,port:Qn(k,p),server:k}}catch(P){throw await V(),P}}function pn(e){let t=fn(e);return t&&gn(t)?"webpack":"turbopack"}function ln(e){return e==="webpack"?{webpack:!0}:{turbopack:!0}}function fn(e){for(let t of an){let n=G(e,t);if(F(n))return U(n,"utf8")}return null}function gn(e){return e.includes(cn)?!0:un.test(e)&&dn.some(t=>t.test(e))}function mn(e){let t=(n,i,s)=>{yn(n.url,e.bridgePath)||e.handleUpgrade(n,i,s).catch(o=>{console.error(o),i.destroyed||i.destroy()})};return e.server.on("upgrade",t),()=>e.server.off("upgrade",t)}function yn(e,t){return new URL(e??"/","http://localhost").pathname===t}function Sn(e=ee){if(e===ee)return Ge;let t=(e.startsWith("/")?e:`/${e}`).replace(/\/+$/,"");return t.endsWith("/bridge")?`${t.slice(0,-7)}/health`:t?`${t}/health`:"/health"}function In(e){let t=JSON.stringify({basePath:e.basePath,launch_id:e.launch?.launchId,snapshot_id:e.launch?.snapshotId,wsPath:e.bridgePath,bridge_session_key:e.bridgeSessionKey,defer_initial_sync:!0,runtime_versions:e.runtimeVersions??En()});return`<script type="module" ${Qe}>import { startSiteEditAutoBootstrap } from ${JSON.stringify(rn)};void startSiteEditAutoBootstrap(window, ${t}).catch(() => undefined);</script>`}function En(){return{bridge:Ie("@vcp-dev/site-edit-bridge"),contracts:Ie("@vcp-dev/contracts"),engine:Ie("@vcp-dev/site-edit-engine")}}function Ie(e){let t=Le(import.meta.url);try{let n=t.resolve(e),i=wn(n,e);if(!i)return;let s=JSON.parse(U(i,"utf8"));return typeof s.version=="string"?s.version:void 0}catch{return}}function wn(e,t){let n=z.parse(e).root,i=J(e);for(;i&&i!==n;){let s=G(i,"package.json");if(F(s))try{if(JSON.parse(U(s,"utf8")).name===t)return s}catch{return}i=J(i)}}function xn(e,t){if(e.includes(Qe))return e;let n=In(t),i=/<\/body\s*>/i.exec(e);return i?`${e.slice(0,i.index)}${n}${e.slice(i.index)}`:`${e}${n}`}function Ai(e,t=J(ze(import.meta.url)),n=F){return Ye(e,t,n)?.path??null}function Ye(e,t=J(ze(import.meta.url)),n=F){let i=new URL(e??"/","http://localhost").pathname;if(!i.startsWith(te))return null;let s=i.slice(te.length);if(!hn.has(s))return null;let o=Ce($n(t),s);if(qe(t)!=="src")return{path:o,requiresTranspile:!1};let r=Ce(t,s.replace(/\.js$/,".ts"));return n(r)?{path:r,requiresTranspile:!0}:{path:o,requiresTranspile:!1}}async function Cn(e,t){let n=Ye(e.url);if(!n)return!1;if(!F(n.path))return t.writeHead(404),t.end("site edit client asset not found"),!0;let i=n.requiresTranspile?await vn(U(n.path,"utf8")):U(n.path);return t.writeHead(200,{"cache-control":"no-store","content-type":"text/javascript; charset=utf-8"}),t.end(i),!0}async function vn(e){let t=await import("typescript");return t.transpileModule(e,{compilerOptions:{module:t.ModuleKind.ES2022,target:t.ScriptTarget.ES2022}}).outputText}async function bn({basePath:e,bridgePath:t,bridgeHealthPath:n,bridgeSessionKey:i,getBridgeHealth:s,launch:o,runRenderProbe:r,handle:c,request:p,response:a}){if(Rn(p.url,e)){a.statusCode=404,a.end();return}if(await Pn(p,a,n,s,o,r)||await Cn(p,a))return;let l=Hn(p),u=Nn(p),S=l||u?Dn(a,{basePath:e,bridgePath:t,bridgeSessionKey:i,patchNextDevChunk:u,launch:{...o}}):()=>{};try{await c(p,a)}catch(d){throw S(),d}}function Rn(e,t){let n=(e??"/").split(/[?#]/,1)[0]??"/";if(!/(\\|\/\/)/.test(n))return!1;let i;try{i=decodeURIComponent(n).replace(/\\/g,"/").replace(/\/{2,}/g,"/")}catch{return!1}let s=new URL(i,"http://namespace.invalid").pathname,o=t.replace(/\/+$/,"");return(o&&(s===o||s.startsWith(o+"/"))?s.slice(o.length)||"/":s).startsWith("/.vcp")}function _n(e){let t=e instanceof Error?e.message:String(e),n=e&&typeof e=="object"&&"code"in e?e.code:void 0;return/\.next[/\\]/.test(t)||/chunks[/\\]ssr[/\\]/.test(t)?n==="ENOENT"||n==="MODULE_NOT_FOUND"?{verdict:"artifact_broken",detail:t}:t.includes("Cannot find module")?{verdict:"artifact_broken",detail:t}:{verdict:"inconclusive",detail:t}:{verdict:"inconclusive",detail:t}}async function kn(e){let t=new xe.IncomingMessage(new We);t.method="GET",t.url=$e,t.headers={host:Je};let n=new xe.ServerResponse(t);n.assignSocket(new We);try{return await e.renderToHTML(t,n,$e,{}),{verdict:"ok"}}catch(i){return _n(i)}finally{try{let i=n.socket;i&&(n.detachSocket(i),i.destroy())}catch{}}}function Tn(e){return new URL(e??"/","http://localhost").searchParams.get(sn)===on}async function Pn(e,t,n,i,s,o){if(e.method!=="GET"||new URL(e.url??"/","http://localhost").pathname!==n)return!1;let c=i(),p=Tn(e.url)?await o():void 0,a={...c,launch:s,...p?{render:p}:{}};return t.writeHead(c.ok?200:503,{"cache-control":"no-store","content-type":"application/json; charset=utf-8"}),t.end(JSON.stringify(a)),!0}function An(e){return{ok:!1,bridgePath:e,runtimeReady:!1,routesIndexed:0,sessionRequired:!0}}function Hn(e){return On(e)?(e.headers["accept-encoding"]="identity",!0):!1}function Nn(e){return Mn(e)?(e.headers["accept-encoding"]="identity",!0):!1}function On(e){if(e.method!=="GET")return!1;let t=new URL(e.url??"/","http://localhost");if(e.headers["x-template-id"]!==void 0&&!t.searchParams.has("template_id"))return!1;let n=t.pathname;if(n.startsWith("/_next/")||n.startsWith(te)||n===ee||n===Ge)return!1;let i=e.headers.accept??"";return i===""||i.includes("text/html")}function Mn(e){if(e.method!=="GET"||!String(e.headers["user-agent"]??"").includes("Firefox"))return!1;let n=new URL(e.url??"/","http://localhost").pathname;return n.startsWith("/_next/static/chunks/")&&n.endsWith(".js")}function Dn(e,t){let n=[],i=e,s=i.flushHeaders.bind(e),o=i.write.bind(e),r=i.end.bind(e),c=!1;i.flushHeaders=()=>{};let p=()=>{if(t.patchNextDevChunk||c)return!1;let a=Buffer.concat(n);if(!/<body\b[^>]*>/iu.test(a.toString("utf8")))return!1;let l=Ve(e,a,t);return l!==a&&!e.headersSent&&e.removeHeader("content-length"),o(l),n.length=0,c=!0,!0};return i.write=(a,l,u)=>c?(a!==void 0&&o(Ee(a,we(l))),X(l),X(u),!0):(a!==void 0&&(n.push(Ee(a,we(l))),p()),X(l),X(u),!0),i.end=(a,l,u)=>{let S=typeof a=="function"?void 0:a;if(c)return i.write=o,i.end=r,i.flushHeaders=s,S===void 0?typeof a=="function"?r(a):typeof l=="function"?r(l):typeof u=="function"?r(u):r():typeof l=="function"?r(S,l):typeof u=="function"?r(S,l,u):r(S,l);S!==void 0&&n.push(Ee(S,we(l))),i.write=o,i.end=r,i.flushHeaders=s;let d=Buffer.concat(n),f=Ve(e,d,t);f!==d&&!e.headersSent&&e.removeHeader("content-length");let m=typeof a=="function"?a:typeof l=="function"?l:typeof u=="function"?u:void 0;return m?r(f,m):r(f)},()=>{i.write=o,i.end=r,i.flushHeaders=s}}function Ve(e,t,n){if(jn(e,t))return Buffer.from(xn(t.toString("utf8"),n));if(n.patchNextDevChunk&&Un(e)){let i=t.toString("utf8"),s=Fn(i);if(s!==i)return Buffer.from(s)}return t}function Bn(){let e=new Uint8Array(32);return globalThis.crypto.getRandomValues(e),Buffer.from(e).toString("base64url")}function jn(e,t){if(e.statusCode<200||e.statusCode>=300)return!1;let n=e.getHeader("content-type"),i=Array.isArray(n)?n.join(";"):String(n??"");return t.toString("utf8",0,256).includes("<html")&&(i===""||i.includes("text/html"))}function Un(e){if(e.statusCode<200||e.statusCode>=300)return!1;let t=e.getHeader("content-type"),n=Array.isArray(t)?t.join(";"):String(t??"");return n===""||n.includes("javascript")||n.includes("ecmascript")}function Fn(e){return[["debugChannel = createDebugChannel(undefined);","debugChannel = undefined;"],["if (isStreamErrorOrUnfinished(ctr)) {","if (false) {"],["return ctr.desiredSize === null || ctr.desiredSize < 0;","return false;"],[["findSourceMapURL: _appfindsourcemapurl.findSourceMapURL,"," debugChannel,"," startTime: 0"].join(`
4
+ `),r.destroy();return}p.authenticatedByHeader&&n.add(o),t.handleUpgrade(o,r,c,a=>{t.emit("connection",a,o)})};return e.server.on("upgrade",s),t.on("connection",(o,r)=>{if(n.has(r)){i(o);return}Mt(o,e.sessionKey,()=>{i(o)})}),t.stop=()=>{e.server.off("upgrade",s);for(let o of t.clients)o.close(1001,"bridge stopped");t.close()},t}var ge=class{constructor(t){this.socket=t,this.onmessage=null,this.onclose=null,t.on("error",()=>{}),t.on("message",n=>{this.onmessage?.({data:n.toString()})}),t.on("close",()=>{this.onclose?.()})}send(t){if(this.socket.readyState===Me.OPEN){if(this.socket.bufferedAmount+Buffer.byteLength(t,"utf8")>bt){this.socket.close(1013,"bridge backpressure");return}this.socket.send(t)}}close(t,n){this.socket.close(t,n)}};function Ht(e,t){return new URL(e.url??"/","http://localhost").pathname===t.path}function Ot(e,t){if(new URL(e.url??"/","http://localhost").searchParams.has("vcp_bridge_key"))return null;let i=he(e.headers["x-vcp-site-edit-key"]),s=Fe(i,t.sessionKey),o=he(e.headers.host),r=he(e.headers.origin);return o&&!Dt(o,t.host,r)?null:r?jt(r,o,t.allowedOrigins)?{authenticatedByHeader:s}:null:s?{authenticatedByHeader:!0}:null}function Mt(e,t,n){let i=setTimeout(()=>{e.close(1008,"bridge authentication timeout")},vt),s,o=()=>{clearTimeout(i),e.off("message",s),e.off("close",o)},r=()=>{o(),e.close(1008,"bridge authentication failed")};s=c=>{try{let p=C.parseMessage(c.toString());if(p.type!=="auth"||!Fe(p.payload.key,t)){r();return}o(),e.readyState===Me.OPEN&&e.send(C.stringifyMessage({type:"auth-ok",payload:{ok:!0}})),n()}catch{r()}},e.on("message",s),e.on("close",o)}function Fe(e,t){if(!e)return!1;let n=Buffer.from(e),i=Buffer.from(t);return n.length===i.length&&pt(n,i)}function Dt(e,t,n){let i=Oe(e),s=Oe(t);return i===s||He(s)&&He(i)&&(!n||me(n,e))||Bt(s)&&(!n||me(n,e))}function Bt(e){return e==="0.0.0.0"||e==="::"}function He(e){return e==="localhost"||e==="127.0.0.1"||e==="::1"}function jt(e,t,n){return n.includes(e)||(t?me(e,t):!1)}function me(e,t){try{return new URL(e).host===Ke(t)}catch{return!1}}function Oe(e){let t=Ke(e);return t.startsWith("[")?t.slice(1,t.indexOf("]")):t.split(":").length-1===1?t.split(":",1)[0]??"":t}function Ke(e){return e.trim().toLowerCase()}function he(e){return Array.isArray(e)?e[0]:e}function Ut(){return ht(32).toString("base64url")}function Ft(e){let t=e.replaceAll("\\","/");return t===pe||t.endsWith(`/${pe}`)}var Vt="SITE_EDIT_ENGINE_UNAVAILABLE",Lt=5e3,qt=1024,zt="VCP_SITE_EDIT_ENGINE_MAX_HEAP_MB",Jt=3,Gt=10*6e4,Qt=1012;function Ie(e,t,n={}){let i=je(t),{onSnapshotIdChanged:s,onHealthChanged:o,...r}=i,c={options:r},p=n.maxHeapMb??Xt(process.env[zt])??qt,a=n.maxRestarts??Jt,l=n.restartWindowMs??Gt,u="starting",S,d=0,f=[],m=null,x=0,w=new Map,E=new Set,K,D,W=new Promise((h,g)=>{K=h,D=g});W.catch(()=>{});let R=h=>{let g=new Error(`VCP site edit preview bridge runtime is not ready: ${h}`);return g.code=Vt,g},$=h=>{for(let g of w.values())g.reject(h);w.clear()},k=h=>{switch(h.type){case"ready":m=h.health,u==="starting"?(u="ready",K()):u==="restarting"&&(u="ready",console.warn("[vcp-site-edit] engine worker restarted"));return;case"start-failed":u==="starting"&&T(ne(h.error));return;case"result":{let g=w.get(h.id);if(!g)return;w.delete(h.id),h.ok?g.resolve(h.value):g.reject(ne(h.error));return}case"event":for(let g of E)try{g(h.event)}catch(I){console.warn(`[vcp-site-edit] engine event listener failed: ${I instanceof Error?I.message:String(I)}`)}return;case"health":m=h.health;return;case"snapshot-id-changed":c.options.snapshotId=h.next;try{s?.(h.next,h.previous)}catch(g){console.warn(`[vcp-site-edit] onSnapshotIdChanged callback failed: ${g instanceof Error?g.message:String(g)}`)}return}},B=()=>{let h=d+=1,g=n.workerUrl??new URL("./engine-worker.js",import.meta.url),I=new $t(Yt(g),{workerData:c,resourceLimits:{maxOldGenerationSizeMb:p},...n.execArgv?{execArgv:n.execArgv}:{}});I.unref();let A=()=>h===d;I.on("message",v=>{A()&&k(v)}),I.on("error",v=>{A()&&T(v instanceof Error?v:new Error(String(v)))}),I.on("exit",v=>{A()&&T(new Error(`engine worker exited with code ${v}`))}),S=I,n.onWorker?.(I)},T=h=>{if(u==="stopped"||u==="failed")return;if($(R(h.message)),m=null,u==="starting"){u="failed",console.error(`[vcp-site-edit] engine worker failed to start: ${h.message}`),D(h);return}let g=Date.now();for(;f.length>0&&g-f[0]>l;)f.shift();if(f.length>=a){u="failed",console.error(`[vcp-site-edit] engine worker stopped unexpectedly and exhausted ${a} restarts: ${h.message}`);return}f.push(g),u="restarting";for(let I of P.clients)I.close(Qt,"site edit engine restarting");console.error(`[vcp-site-edit] engine worker stopped unexpectedly, restarting (${f.length}/${a}): ${h.message}`),B()},V=(h,g)=>{if(u==="failed"||u==="stopped"||u==="restarting")return Promise.reject(R(u));let I=x+=1;return new Promise((A,v)=>{w.set(I,{resolve:A,reject:v});let Ze={type:"call",id:I,method:h,args:g};S.postMessage(Ze)})},j=Object.fromEntries(be.map(h=>[h,(...g)=>V(h,g)])),P=Se({server:e,path:i.path,sessionKey:i.sessionKey,host:i.host,allowedOrigins:i.allowedOrigins,engine:{...j,subscribe(h){return E.add(h),()=>E.delete(h)}}});return B(),{getHealth(){return u==="ready"&&m?m:{ok:!1,bridgePath:i.path,runtimeReady:!1,routesIndexed:m?.routesIndexed??0,sessionRequired:!!i.sessionKey}},stop(){if(u==="stopped")return;let h=u==="starting";u="stopped",P.stop(),h&&D(R("bridge stopped")),$(R("bridge stopped")),E.clear();let g=S,I={type:"stop"};g.postMessage(I);let A=setTimeout(()=>{g.terminate()},Lt);A.unref(),g.once("exit",()=>clearTimeout(A))},whenReady(){return W},eventListeners:E}}function Yt(e){if(!e.pathname.endsWith(".ts"))return e;let t=Wt(Kt(import.meta.url).resolve("tsx/esm/api")).href,n=[`import { tsImport } from ${JSON.stringify(t)};`,`await tsImport(${JSON.stringify(e.href)}, ${JSON.stringify(e.href)});`].join(`
5
+ `);return new URL(`data:text/javascript,${encodeURIComponent(n)}`)}function Xt(e){if(!e||!/^\d+$/.test(e.trim()))return;let t=Number(e.trim());return Number.isSafeInteger(t)&&t>0?t:void 0}var en="next",tn="VCP_SITE_EDIT_ENGINE_IN_PROCESS",Je="127.0.0.1",nn=3e3,ee="/__vcp/site-edit/bridge",Ge="/__vcp/site-edit/health",sn="probe",on="render",$e="/_error",te="/__vcp/site-edit/client/",rn=`${te}auto-bootstrap.js`,Qe='data-vcp-site-edit-bootstrap="true"',an=["next.config.ts","next.config.mts","next.config.cts","next.config.js","next.config.mjs","next.config.cjs"],cn="@vcp-dev/site-edit-engine/webpack-loader",un=/@vcp\/site-edit-engine\/(?:webpack-loader|site-edit-instrumentation-loader)/,dn=[/\bconfig\.webpack\s*=/,/\bwebpack\s*\([^)]*\)\s*\{/,/\bwebpack\s*:\s*(?:async\s*)?(?:\([^)]*\)|[A-Za-z_$][\w$]*)?\s*=>/,/\bwebpack\s*:\s*(?:async\s+)?function\b/],hn=new Set(["auto-bootstrap.js","client.js","composition-key.js","designer-trace.js","document-codec.js","property-preview.js","protocol.js","window-message.js"]);async function Pi(e={},t={}){let n=t.process??process,i=t.createServer??Re.createServer,s=t.attachBridgeServer??(n.env[tn]==="1"?Be:Ie),o=t.loadNext??Wn,r=z.resolve(e.projectRoot??process.cwd()),c=e.host??Je,p=e.port??qn(n.env.PORT)??nn,a=e.bridgePath??ee,l=Sn(a),u=Bn(),S=e.basePath??n.env.VCP_SITE_PREVIEW_BASE_PATH??"/",d=(e.tenantId??n.env.VCP_TENANT_ID)?.trim()||void 0,f=await o(r),m=pn(r),x=f({dev:!0,dir:r,hostname:c,port:p,...ln(m)}),w=x.getRequestHandler(),E=e.siteId??n.env.VCP_SITE_ID??"018f6f4d-a9b8-7120-8000-000000000120",K=e.snapshotId??n.env.VCP_SNAPSHOT_ID??Ln(r),D=e.historyRoot??n.env.VCP_SITE_EDIT_HISTORY_ROOT,W=D?.trim()?z.resolve(D):void 0,R=null,$={launchId:Zt(),pid:process.pid,snapshotId:K},k=i((P,h)=>{bn({basePath:S,bridgePath:a,bridgeHealthPath:l,bridgeSessionKey:u,getBridgeHealth:()=>R?.getHealth()??An(a),launch:$,runRenderProbe:()=>kn(x),handle:w,request:P,response:h}).catch(g=>{console.error(g),h.headersSent||(h.statusCode=500),h.end("site edit preview request failed")})}),B=null,T=null,V=()=>T||(Z(()=>n.off("SIGINT",j)),Z(()=>n.off("SIGTERM",j)),Z(()=>B?.()),B=null,Z(()=>R?.stop()),R=null,T=Promise.allSettled([Jn(k),Gn(()=>x.close())]).then(()=>{}),T),j=()=>{V()};try{return await x.prepare(),R=s(k,{...d?{tenantId:d}:{},siteId:E,snapshotId:K,projectRoot:r,basePath:S,host:c,port:p,path:a,sessionKey:u,...W?{historyRoot:W}:{},onSnapshotIdChanged:P=>{$.snapshotId=P}}),B=mn({server:k,bridgePath:a,handleUpgrade:x.getUpgradeHandler()}),n.on("SIGINT",j),n.on("SIGTERM",j),await R.whenReady?.(),await zn(k,p,c),{bundler:m,close:V,host:c,port:Qn(k,p),server:k}}catch(P){throw await V(),P}}function pn(e){let t=fn(e);return t&&gn(t)?"webpack":"turbopack"}function ln(e){return e==="webpack"?{webpack:!0}:{turbopack:!0}}function fn(e){for(let t of an){let n=G(e,t);if(F(n))return U(n,"utf8")}return null}function gn(e){return e.includes(cn)?!0:un.test(e)&&dn.some(t=>t.test(e))}function mn(e){let t=(n,i,s)=>{yn(n.url,e.bridgePath)||e.handleUpgrade(n,i,s).catch(o=>{console.error(o),i.destroyed||i.destroy()})};return e.server.on("upgrade",t),()=>e.server.off("upgrade",t)}function yn(e,t){return new URL(e??"/","http://localhost").pathname===t}function Sn(e=ee){if(e===ee)return Ge;let t=(e.startsWith("/")?e:`/${e}`).replace(/\/+$/,"");return t.endsWith("/bridge")?`${t.slice(0,-7)}/health`:t?`${t}/health`:"/health"}function In(e){let t=JSON.stringify({basePath:e.basePath,launch_id:e.launch?.launchId,snapshot_id:e.launch?.snapshotId,wsPath:e.bridgePath,bridge_session_key:e.bridgeSessionKey,defer_initial_sync:!0,runtime_versions:e.runtimeVersions??wn()});return`<script type="module" ${Qe}>import { startSiteEditAutoBootstrap } from ${JSON.stringify(rn)};void startSiteEditAutoBootstrap(window, ${t}).catch(() => undefined);</script>`}function wn(){return{bridge:we("@vcp-dev/site-edit-bridge"),contracts:we("@vcp-dev/contracts"),engine:we("@vcp-dev/site-edit-engine")}}function we(e){let t=Le(import.meta.url);try{let n=t.resolve(e),i=En(n,e);if(!i)return;let s=JSON.parse(U(i,"utf8"));return typeof s.version=="string"?s.version:void 0}catch{return}}function En(e,t){let n=z.parse(e).root,i=J(e);for(;i&&i!==n;){let s=G(i,"package.json");if(F(s))try{if(JSON.parse(U(s,"utf8")).name===t)return s}catch{return}i=J(i)}}function xn(e,t){if(e.includes(Qe))return e;let n=In(t),i=/<\/body\s*>/i.exec(e);return i?`${e.slice(0,i.index)}${n}${e.slice(i.index)}`:`${e}${n}`}function Ai(e,t=J(ze(import.meta.url)),n=F){return Ye(e,t,n)?.path??null}function Ye(e,t=J(ze(import.meta.url)),n=F){let i=new URL(e??"/","http://localhost").pathname;if(!i.startsWith(te))return null;let s=i.slice(te.length);if(!hn.has(s))return null;let o=Ce($n(t),s);if(qe(t)!=="src")return{path:o,requiresTranspile:!1};let r=Ce(t,s.replace(/\.js$/,".ts"));return n(r)?{path:r,requiresTranspile:!0}:{path:o,requiresTranspile:!1}}async function Rn(e,t){let n=Ye(e.url);if(!n)return!1;if(!F(n.path))return t.writeHead(404),t.end("site edit client asset not found"),!0;let i=n.requiresTranspile?await Cn(U(n.path,"utf8")):U(n.path);return t.writeHead(200,{"cache-control":"no-store","content-type":"text/javascript; charset=utf-8"}),t.end(i),!0}async function Cn(e){let t=await import("typescript");return t.transpileModule(e,{compilerOptions:{module:t.ModuleKind.ES2022,target:t.ScriptTarget.ES2022}}).outputText}async function bn({basePath:e,bridgePath:t,bridgeHealthPath:n,bridgeSessionKey:i,getBridgeHealth:s,launch:o,runRenderProbe:r,handle:c,request:p,response:a}){if(vn(p.url,e)){a.statusCode=404,a.end();return}if(await Pn(p,a,n,s,o,r)||await Rn(p,a))return;let l=Nn(p),u=Hn(p),S=l||u?Dn(a,{basePath:e,bridgePath:t,bridgeSessionKey:i,patchNextDevChunk:u,launch:{...o}}):()=>{};try{await c(p,a)}catch(d){throw S(),d}}function vn(e,t){let n=(e??"/").split(/[?#]/,1)[0]??"/";if(!/(\\|\/\/)/.test(n))return!1;let i;try{i=decodeURIComponent(n).replace(/\\/g,"/").replace(/\/{2,}/g,"/")}catch{return!1}let s=new URL(i,"http://namespace.invalid").pathname,o=t.replace(/\/+$/,"");return(o&&(s===o||s.startsWith(o+"/"))?s.slice(o.length)||"/":s).startsWith("/.vcp")}function _n(e){let t=e instanceof Error?e.message:String(e),n=e&&typeof e=="object"&&"code"in e?e.code:void 0;return/\.next[/\\]/.test(t)||/chunks[/\\]ssr[/\\]/.test(t)?n==="ENOENT"||n==="MODULE_NOT_FOUND"?{verdict:"artifact_broken",detail:t}:t.includes("Cannot find module")?{verdict:"artifact_broken",detail:t}:{verdict:"inconclusive",detail:t}:{verdict:"inconclusive",detail:t}}async function kn(e){let t=new Re.IncomingMessage(new We);t.method="GET",t.url=$e,t.headers={host:Je};let n=new Re.ServerResponse(t);n.assignSocket(new We);try{return await e.renderToHTML(t,n,$e,{}),{verdict:"ok"}}catch(i){return _n(i)}finally{try{let i=n.socket;i&&(n.detachSocket(i),i.destroy())}catch{}}}function Tn(e){return new URL(e??"/","http://localhost").searchParams.get(sn)===on}async function Pn(e,t,n,i,s,o){if(e.method!=="GET"||new URL(e.url??"/","http://localhost").pathname!==n)return!1;let c=i(),p=Tn(e.url)?await o():void 0,a={...c,launch:s,...p?{render:p}:{}};return t.writeHead(c.ok?200:503,{"cache-control":"no-store","content-type":"application/json; charset=utf-8"}),t.end(JSON.stringify(a)),!0}function An(e){return{ok:!1,bridgePath:e,runtimeReady:!1,routesIndexed:0,sessionRequired:!0}}function Nn(e){return On(e)?(e.headers["accept-encoding"]="identity",!0):!1}function Hn(e){return Mn(e)?(e.headers["accept-encoding"]="identity",!0):!1}function On(e){if(e.method!=="GET")return!1;let t=new URL(e.url??"/","http://localhost");if(e.headers["x-template-id"]!==void 0&&!t.searchParams.has("template_id"))return!1;let n=t.pathname;if(n.startsWith("/_next/")||n.startsWith(te)||n===ee||n===Ge)return!1;let i=e.headers.accept??"";return i===""||i.includes("text/html")}function Mn(e){if(e.method!=="GET"||!String(e.headers["user-agent"]??"").includes("Firefox"))return!1;let n=new URL(e.url??"/","http://localhost").pathname;return n.startsWith("/_next/static/chunks/")&&n.endsWith(".js")}function Dn(e,t){let n=[],i=e,s=i.flushHeaders.bind(e),o=i.write.bind(e),r=i.end.bind(e),c=!1;i.flushHeaders=()=>{};let p=()=>{if(t.patchNextDevChunk||c)return!1;let a=Buffer.concat(n);if(!/<body\b[^>]*>/iu.test(a.toString("utf8")))return!1;let l=Ve(e,a,t);return l!==a&&!e.headersSent&&e.removeHeader("content-length"),o(l),n.length=0,c=!0,!0};return i.write=(a,l,u)=>c?(a!==void 0&&o(Ee(a,xe(l))),X(l),X(u),!0):(a!==void 0&&(n.push(Ee(a,xe(l))),p()),X(l),X(u),!0),i.end=(a,l,u)=>{let S=typeof a=="function"?void 0:a;if(c)return i.write=o,i.end=r,i.flushHeaders=s,S===void 0?typeof a=="function"?r(a):typeof l=="function"?r(l):typeof u=="function"?r(u):r():typeof l=="function"?r(S,l):typeof u=="function"?r(S,l,u):r(S,l);S!==void 0&&n.push(Ee(S,xe(l))),i.write=o,i.end=r,i.flushHeaders=s;let d=Buffer.concat(n),f=Ve(e,d,t);f!==d&&!e.headersSent&&e.removeHeader("content-length");let m=typeof a=="function"?a:typeof l=="function"?l:typeof u=="function"?u:void 0;return m?r(f,m):r(f)},()=>{i.write=o,i.end=r,i.flushHeaders=s}}function Ve(e,t,n){if(jn(e,t))return Buffer.from(xn(t.toString("utf8"),n));if(n.patchNextDevChunk&&Un(e)){let i=t.toString("utf8"),s=Fn(i);if(s!==i)return Buffer.from(s)}return t}function Bn(){let e=new Uint8Array(32);return globalThis.crypto.getRandomValues(e),Buffer.from(e).toString("base64url")}function jn(e,t){if(e.statusCode<200||e.statusCode>=300)return!1;let n=e.getHeader("content-type"),i=Array.isArray(n)?n.join(";"):String(n??"");return t.toString("utf8",0,256).includes("<html")&&(i===""||i.includes("text/html"))}function Un(e){if(e.statusCode<200||e.statusCode>=300)return!1;let t=e.getHeader("content-type"),n=Array.isArray(t)?t.join(";"):String(t??"");return n===""||n.includes("javascript")||n.includes("ecmascript")}function Fn(e){return[["debugChannel = createDebugChannel(undefined);","debugChannel = undefined;"],["if (isStreamErrorOrUnfinished(ctr)) {","if (false) {"],["return ctr.desiredSize === null || ctr.desiredSize < 0;","return false;"],[["findSourceMapURL: _appfindsourcemapurl.findSourceMapURL,"," debugChannel,"," startTime: 0"].join(`
6
6
  `),["unstable_allowPartialStream: true,"," debugChannel,"," startTime: 0"].join(`
7
- `)],[["findSourceMapURL: _appfindsourcemapurl.findSourceMapURL,"," debugChannel,"," startTime: 0"].join("\\n"),["unstable_allowPartialStream: true,"," debugChannel,"," startTime: 0"].join("\\n")],["debugChannel: createDebugChannel && createDebugChannel(requestHeaders)","debugChannel: undefined"],["debugChannel: createDebugChannel && createDebugChannel(headers)","debugChannel: undefined"]].reduce((n,[i,s])=>Kn(n,i,s),e)}function Kn(e,t,n){if(n.length>t.length)throw new Error("Replacement must not be longer than the search string.");return e.replaceAll(t,n.padEnd(t.length," "))}function Ee(e,t){return Buffer.isBuffer(e)?e:e instanceof Uint8Array?Buffer.from(e):Buffer.from(String(e),t)}function we(e){return typeof e=="string"?e:void 0}function X(e){typeof e=="function"&&e()}async function Wn(e){let n=Le(G(e,"package.json"))(en);return n.default??n}function $n(e){return qe(e)!=="src"?e:Ce(Vn(e),"dist")}function Vn(e){return Xe(e)?z.posix.dirname(e):J(e)}function Ce(e,t){return Xe(e)?z.posix.join(e,t):G(e,t)}function Xe(e){return e.includes("/")&&!e.includes("\\")}function Ln(e){let t=G(e,".vcp/current-snapshot.json");if(!F(t))return"sandbox_worktree";try{let n=JSON.parse(U(t,"utf8"));return typeof n.snapshot_id=="string"&&n.snapshot_id?n.snapshot_id:typeof n.snapshotId=="string"&&n.snapshotId?n.snapshotId:"sandbox_worktree"}catch{return"sandbox_worktree"}}function qn(e){if(!e)return null;let t=Number.parseInt(e,10);return Number.isInteger(t)&&t>0&&t<=65535?t:null}function zn(e,t,n){return new Promise((i,s)=>{e.once("error",s),e.listen(t,n,()=>{e.off("error",s),i()})})}function Jn(e){return new Promise(t=>{e.close(()=>t())})}function Z(e){try{e()}catch{}}function Gn(e){try{return e()}catch(t){return Promise.reject(t)}}function Qn(e,t){let n=e.address();return typeof n=="object"&&n?n.port:t}export{mn as attachNextDevUpgradeHandler,Se as attachSiteEditBridgeServerInWorker,_n as classifySiteEditRenderProbeError,In as createSiteEditAutoBootstrapHtmlSnippet,xn as injectSiteEditAutoBootstrap,Tn as isSiteEditRenderProbeRequested,Fn as patchNextFirefoxDevChunk,Nn as prepareFirefoxNextDevChunkPatchRequest,Hn as prepareSiteEditHtmlInjectionRequest,Sn as resolveSiteEditBridgeHealthPath,Ye as resolveSiteEditClientAsset,Ai as resolveSiteEditClientAssetPath,pn as resolveSiteEditNextDevBundler,kn as runSiteEditRenderProbe,Pi as startSiteEditNextDevServer,vn as transpileSiteEditClientSource};
7
+ `)],[["findSourceMapURL: _appfindsourcemapurl.findSourceMapURL,"," debugChannel,"," startTime: 0"].join("\\n"),["unstable_allowPartialStream: true,"," debugChannel,"," startTime: 0"].join("\\n")],["debugChannel: createDebugChannel && createDebugChannel(requestHeaders)","debugChannel: undefined"],["debugChannel: createDebugChannel && createDebugChannel(headers)","debugChannel: undefined"]].reduce((n,[i,s])=>Kn(n,i,s),e)}function Kn(e,t,n){if(n.length>t.length)throw new Error("Replacement must not be longer than the search string.");return e.replaceAll(t,n.padEnd(t.length," "))}function Ee(e,t){return Buffer.isBuffer(e)?e:e instanceof Uint8Array?Buffer.from(e):Buffer.from(String(e),t)}function xe(e){return typeof e=="string"?e:void 0}function X(e){typeof e=="function"&&e()}async function Wn(e){let n=Le(G(e,"package.json"))(en);return n.default??n}function $n(e){return qe(e)!=="src"?e:Ce(Vn(e),"dist")}function Vn(e){return Xe(e)?z.posix.dirname(e):J(e)}function Ce(e,t){return Xe(e)?z.posix.join(e,t):G(e,t)}function Xe(e){return e.includes("/")&&!e.includes("\\")}function Ln(e){let t=G(e,".vcp/current-snapshot.json");if(!F(t))return"sandbox_worktree";try{let n=JSON.parse(U(t,"utf8"));return typeof n.snapshot_id=="string"&&n.snapshot_id?n.snapshot_id:typeof n.snapshotId=="string"&&n.snapshotId?n.snapshotId:"sandbox_worktree"}catch{return"sandbox_worktree"}}function qn(e){if(!e)return null;let t=Number.parseInt(e,10);return Number.isInteger(t)&&t>0&&t<=65535?t:null}function zn(e,t,n){return new Promise((i,s)=>{e.once("error",s),e.listen(t,n,()=>{e.off("error",s),i()})})}function Jn(e){return new Promise(t=>{e.close(()=>t())})}function Z(e){try{e()}catch{}}function Gn(e){try{return e()}catch(t){return Promise.reject(t)}}function Qn(e,t){let n=e.address();return typeof n=="object"&&n?n.port:t}export{mn as attachNextDevUpgradeHandler,Ie as attachSiteEditBridgeServerInWorker,_n as classifySiteEditRenderProbeError,In as createSiteEditAutoBootstrapHtmlSnippet,xn as injectSiteEditAutoBootstrap,Tn as isSiteEditRenderProbeRequested,Fn as patchNextFirefoxDevChunk,Hn as prepareFirefoxNextDevChunkPatchRequest,Nn as prepareSiteEditHtmlInjectionRequest,Sn as resolveSiteEditBridgeHealthPath,Ye as resolveSiteEditClientAsset,Ai as resolveSiteEditClientAssetPath,pn as resolveSiteEditNextDevBundler,kn as runSiteEditRenderProbe,Pi as startSiteEditNextDevServer,Cn as transpileSiteEditClientSource};
@@ -21,7 +21,7 @@ export type SiteEditBridgeSessionState = {
21
21
  export declare const SITE_EDIT_COMPOSITION_SESSION_MISMATCH = "SITE_EDIT_COMPOSITION_SESSION_MISMATCH";
22
22
  export declare const SITE_EDIT_COMPOSITION_SESSION_REQUIRED = "SITE_EDIT_COMPOSITION_SESSION_REQUIRED";
23
23
  export declare const SITE_EDIT_COMPOSITION_REINITIALIZE_REQUIRED = "SITE_EDIT_COMPOSITION_REINITIALIZE_REQUIRED";
24
- export type SiteEditBridgeRequestKind = "initialize-session" | "get-document" | "get-history-status" | "get-style-context" | "get-object-edit-context" | "get-class-name-source" | "get-source-tree" | "get-source-file" | "resolve-source-location" | "execute" | "undo" | "redo";
24
+ export type SiteEditBridgeRequestKind = "initialize-session" | "get-document" | "get-history-status" | "get-style-context" | "get-object-edit-context" | "get-class-name-source" | "get-source-tree" | "get-source-file" | "resolve-source-location" | "execute" | "get-operation-result" | "undo" | "redo";
25
25
  type CompositionRequestFields = {
26
26
  /** Current protocol selector; required for every composition-sensitive wire request. */
27
27
  composition: SiteEditCompositionSelector;
@@ -59,7 +59,7 @@ export type SiteEditBridgeRequest = {
59
59
  path: string;
60
60
  } & CompositionRequestFields) | ({
61
61
  id: string;
62
- kind: "execute";
62
+ kind: "execute" | "get-operation-result";
63
63
  request: SiteEditOperationRequest | Record<string, unknown>;
64
64
  } & CompositionRequestFields) | ({
65
65
  id: string;
@@ -129,6 +129,7 @@ export type SiteEditBridgeEngine = {
129
129
  composition: SiteEditCompositionContext;
130
130
  }): Awaitable<SiteEditCommandSuccess<SiteEditSourceLocation>>;
131
131
  execute(request: SiteEditOperationRequest, mutationContext?: SiteEditMutationContext): Awaitable<SiteEditOperationCommandResult>;
132
+ getOperationResult?(request: SiteEditOperationRequest): Awaitable<SiteEditOperationCommandResult | null>;
132
133
  undo(composition: SiteEditCompositionContext): Awaitable<SiteEditOperationCommandResult>;
133
134
  redo(composition: SiteEditCompositionContext): Awaitable<SiteEditOperationCommandResult>;
134
135
  subscribe(listener: (event: SiteEditEvent) => void): () => void;
package/dist/protocol.js CHANGED
@@ -35,6 +35,7 @@ export class SiteEditBridgeTransport {
35
35
  value === "get-source-file" ||
36
36
  value === "resolve-source-location" ||
37
37
  value === "execute" ||
38
+ value === "get-operation-result" ||
38
39
  value === "undo" ||
39
40
  value === "redo");
40
41
  }
@@ -176,7 +177,8 @@ export class SiteEditBridgeSocketServer {
176
177
  this.sendResult(id, payload.kind, result);
177
178
  return;
178
179
  }
179
- case "execute": {
180
+ case "execute":
181
+ case "get-operation-result": {
180
182
  const context = await this.resolveOperationWireContext(payload.request);
181
183
  const payloadContext = await this.resolveWireContext(payload);
182
184
  if (computeSiteEditCompositionKey(context) !==
@@ -184,6 +186,10 @@ export class SiteEditBridgeSocketServer {
184
186
  throw new BridgeProtocolError(SITE_EDIT_COMPOSITION_SESSION_MISMATCH, "The execute request composition does not match its operation composition.");
185
187
  }
186
188
  const request = await this.normalizeOperationRequest(payload.request, context);
189
+ if (payload.kind === "get-operation-result") {
190
+ this.sendResult(id, payload.kind, (await this.options.engine.getOperationResult?.(request)) ?? null);
191
+ return;
192
+ }
187
193
  await this.handleBufferedOperation(id, payload.kind, () => this.options.engine.execute(request));
188
194
  return;
189
195
  }
@@ -392,6 +398,7 @@ function isRequestPayload(payload, options) {
392
398
  case "get-source-file":
393
399
  return typeof payload.path === "string" && compositionOk;
394
400
  case "execute":
401
+ case "get-operation-result":
395
402
  return (compositionOk &&
396
403
  isOperationRequestLike(payload.request) &&
397
404
  (payload.request.mutationContext === undefined ||
package/dist/server.d.ts CHANGED
@@ -64,6 +64,7 @@ export declare class SiteEditBridgeServer {
64
64
  private activeHistorySessionId;
65
65
  private historySessionTransition;
66
66
  private readonly mutationQueue;
67
+ private readonly operationReceipts;
67
68
  private readonly eventListeners;
68
69
  private routes;
69
70
  private compositions;
@@ -96,6 +97,9 @@ export declare class SiteEditBridgeServer {
96
97
  private notifyHealthChanged;
97
98
  private createRuntime;
98
99
  private createBridgeEngine;
100
+ private operationReceiptKey;
101
+ private operationFingerprint;
102
+ private executeWithReceipt;
99
103
  private bindHistorySession;
100
104
  private recordRuntimeVersion;
101
105
  private handleFileChanged;
package/dist/server.js CHANGED
@@ -1,4 +1,4 @@
1
- import te from"node:http";import v from"node:fs";import{createHash as ne,randomBytes as Se,timingSafeEqual as we}from"node:crypto";import g from"node:path";import{WebSocket as ie,WebSocketServer as Ce}from"ws";import{createPreviewSiteEditEngineRuntime as Ee,openFileHistoryStore as Re,resolveManagedPageTemplateComposition as be,scanSiteEditCompositionsFromFiles as xe}from"@vcp-dev/site-edit-engine";import{resolveNextAppRouteId as ve,scanNextAppRouterRoutesFromFiles as ke}from"@vcp-dev/site-edit-engine/next-app-router";import{SiteEditSourceWatcher as _e}from"@vcp-dev/site-edit-engine/source-watcher";function L(t){let e=new Map,n=[],i=new Map,o=[],s=t.pageComposition.status==="supported"?t.pageComposition.placementUnitKeys:[],r=new Map(s.map((a,d)=>[a,d])),c=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},p=t.entries.flatMap((a,d)=>a.dynamicDataSummary?[[d,a.dynamicDataSummary]]:[]),u=new Map(t.entries.map((a,d)=>[a.key,d])),l=[];for(let[a,d]of t.entries.entries()){let f=d.pageCompositionActionScope;if(!f)continue;if(f.kind!=="source-siblings"){l.push([a,{kind:f.kind}]);continue}let _=f.siblingKeys.map(R=>{let b=u.get(R);if(b===void 0)throw new Error("Render entry "+d.key+" references missing source sibling "+R);return b});l.push([a,{kind:"source-siblings",siblingEntryIndexes:_}])}let S=a=>{let d=e.get(a);if(typeof d=="number")return d;let f=n.length;return n.push(a),e.set(a,f),f},j=a=>{let d=null;for(let f of de(a)){let _=`${d??"root"}\0${f}`,R=i.get(_);if(typeof R=="number"){d=R;continue}let b=o.length;o.push([d,S(f)]),i.set(_,b),d=b}if(d===null)throw new Error("Document key must not be empty");return d};return{encoding:"segment-trie-v1",siteId:t.siteId,snapshotId:t.snapshotId,composition:{...t.composition},routeId:t.composition.routeId,version:t.version,pageComposition:c,tokens:n,nodes:o,entries:t.entries.map(a=>{let d=a.pageCompositionUnitKey?r.get(a.pageCompositionUnitKey)??-1:-1;if(a.pageCompositionUnitKey&&d<0)throw new Error(`Render entry ${a.key} references unknown page composition unit ${a.pageCompositionUnitKey}`);return[j(a.key),ue(a.operationSummary),...d>=0?[d]:[]]}),...l.length>0?{pageCompositionActionScopes:l}:{},...t.entries.every(a=>a.parentKey!==void 0)?{entryParentNodeIds:t.entries.map(a=>a.parentKey===null?null:j(a.parentKey))}:{},...p.length>0?{dynamicDataSummaries:p}:{}}}function ue(t){return(t.canUpdateText?1:0)|(t.canInsertChild?2:0)|(t.canMove?4:0)|(t.canRemove?8:0)}function de(t){if(!t)return[];let e=[],n=0,i=z(t,n);if(i<0)return e.push(t),e;for(e.push(t.slice(0,i)),n=i;n<t.length;){if(i=z(t,n+(t.startsWith("::",n)?2:1)),i<0){e.push(t.slice(n));break}e.push(t.slice(n,i)),n=i}return e}function z(t,e){let n=t.indexOf("/",e),i=t.indexOf("::",e);return n<0?i:i<0?n:Math.min(n,i)}var J="SITE_EDIT_COMPOSITION_SESSION_MISMATCH",N="SITE_EDIT_COMPOSITION_SESSION_REQUIRED";var m=class t{constructor(){}static parseMessage(e,n={}){let i=JSON.parse(e);if(!t.isMessage(i,n))throw new Error("Invalid site edit bridge message");return i}static stringifyMessage(e){return JSON.stringify(e)}static extractRequestInfo(e){if(h(e)&&h(e.payload)){let n=typeof e.payload.id=="string"?e.payload.id:"unknown",i=this.isRequestKind(e.payload.kind)?e.payload.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,n={}){return!h(e)||typeof e.type!="string"?!1:e.type==="request"?he(e.payload,n):e.type==="response"||e.type==="error"?h(e.payload)&&typeof e.payload.id=="string":e.type==="event"?h(e.payload)&&h(e.payload.event):e.type==="auth"?h(e.payload)&&typeof e.payload.key=="string":e.type==="auth-ok"&&h(e.payload)&&e.payload.ok===!0}},T=class{constructor(e){this.options=e,this.session={subscribedCompositionKeys:new Set},this.messageQueue=new B,this.eventDispatcher=new F(n=>{this.sendJson(n)}),this.unsubscribe=e.engine.subscribe(n=>{this.handleEngineEvent(n)}),e.socket.onmessage=n=>{try{this.messageQueue.enqueue(()=>this.handleRawMessage(n.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 n=e;if(n.type!=="request")return;let i=n.payload,{id:o}=i;switch(i.kind){case"initialize-session":{let s=H(i),r=await this.resolve(s),c=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:I({...c,data:{...c.data,document:G(c.data.document)}},r.context)}});return}case"get-document":{let s=await this.resolveWireContext(i),r=await this.options.engine.getDocument(s);this.sendResult(o,i.kind,ye(r,s));return}case"get-history-status":{let s=await this.resolveWireContext(i),r=await this.options.engine.getHistoryStatus(s);this.sendResult(o,i.kind,I(r,s));return}case"get-style-context":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getStyleContext(s),s));return}case"get-object-edit-context":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getObjectEditContext(i.key,s,i.selectionRef),s));return}case"get-class-name-source":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getClassNameSource(i.key,s),s));return}case"get-source-tree":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getSourceTree(s),s));return}case"get-source-file":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getSourceFile({path:i.path,composition:s}),s));return}case"resolve-source-location":{let s=await this.resolveWireContext(i),r=I(await this.options.engine.resolveSourceLocation({key:i.key,composition:s}),s);this.sendResult(o,i.kind,r);return}case"execute":{let s=await this.resolveOperationWireContext(i.request),r=await this.resolveWireContext(i);if(w(s)!==w(r))throw new C(J,"The execute request composition does not match its operation composition.");let c=await this.normalizeOperationRequest(i.request,s);await this.handleBufferedOperation(o,i.kind,()=>this.options.engine.execute(c));return}case"undo":case"redo":{let s=await this.resolveWireContext(i);await this.handleBufferedOperation(o,i.kind,()=>i.kind==="undo"?this.options.engine.undo(s):this.options.engine.redo(s));return}}}catch(n){let i=m.extractRequestInfo(e);this.sendJson({type:"error",payload:{...i,message:K(n),code:D(n)}})}}async resolve(e){return this.options.engine.resolveComposition(e)}async resolveAndAssert(e){let n=await this.resolve(e),i=this.session.activeComposition;if(!i)throw new C(N,"Initialize a composition session before issuing this request.");if(w(i)!==w(n.context))throw new C(J,"The request composition does not match the active socket session.");return n.context}async resolveWireContext(e){let n=H(e);return this.resolveAndAssert(n)}async resolveOperationWireContext(e){let n=me(e);return this.resolveAndAssert(n)}activateSession(e){this.session.activeComposition=e,this.session.subscribedCompositionKeys.clear(),this.session.subscribedCompositionKeys.add(w(e))}async normalizeOperationRequest(e,n){let i={...e,composition:Q(n)};if(i.target.kind==="route"){let o=i.target,s=H(o),r=await this.resolveAndAssert(s);i.target={...o,composition:Q(r)}}return i}handleEngineEvent(e){let n=e?.composition;if(!fe(n))return;let i=w(n);this.session.subscribedCompositionKeys.has(i)&&(this.eventDispatcher.push(e),e.type==="site-edit.graph.invalidated"&&i===ge(this.session)&&(this.session.activeComposition=void 0,this.session.subscribedCompositionKeys.delete(i)))}sendResult(e,n,i){this.sendJson({type:"response",payload:{id:e,kind:n,result:i}})}async handleRawMessage(e){try{await this.handleMessage(m.parseMessage(e,{validateOperationRequest:this.options.validateOperationRequest}))}catch(n){let i=Ie(e);this.sendJson({type:"error",payload:{...i,message:K(n),code:D(n)}})}}sendJson(e){this.options.socket.send(m.stringifyMessage(e))}async handleBufferedOperation(e,n,i){this.eventDispatcher.beginBuffering();try{let o=await i();this.sendResult(e,n,o)}catch(o){this.sendJson({type:"error",payload:{id:e,kind:n,message:K(o),code:D(o)}})}finally{this.eventDispatcher.flush()}}},C=class extends Error{constructor(e,n){super(n),this.code=e,this.name="BridgeProtocolError"}},F=class{constructor(e){this.send=e,this.bufferedEvents=null}push(e){let n={type:"event",payload:{event:e}};if(this.bufferedEvents){this.bufferedEvents.push(n);return}this.send(n)}beginBuffering(){this.bufferedEvents=[]}flush(){let e=this.bufferedEvents??[];this.bufferedEvents=null,e.forEach(n=>this.send(n))}},B=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 n=async()=>{this.queued-=1,await e()},i=this.queue.then(n,n);return this.queue=i.then(()=>{},()=>{}),i}};function he(t,e){if(!h(t)||typeof t.id!="string"||!m.isRequestKind(t.kind))return!1;let n=x(t.composition);switch(t.kind){case"initialize-session":return n&&(t.mutationContext===void 0||M(t.mutationContext));case"get-document":case"get-style-context":return n;case"get-object-edit-context":return typeof t.key=="string"&&n&&pe(t.selectionRef);case"get-class-name-source":case"resolve-source-location":return typeof t.key=="string"&&n;case"get-history-status":return n;case"get-source-tree":return n;case"get-source-file":return typeof t.path=="string"&&n;case"execute":return n&&le(t.request)&&(t.request.mutationContext===void 0||M(t.request.mutationContext))&&(e.validateOperationRequest?.(t.request)??!0);case"undo":case"redo":return n&&t.mutationContext===void 0||n&&M(t.mutationContext)}}function pe(t){if(t===void 0)return!0;if(!h(t)||typeof t.key!="string"||t.key.length===0)return!1;let e=t.instanceIndex,n=t.instanceCount;return e!==void 0&&(typeof e!="number"||!Number.isInteger(e)||e<0)||n!==void 0&&(typeof n!="number"||!Number.isInteger(n)||n<=0)||typeof e=="number"&&typeof n=="number"&&e>=n?!1:Object.keys(t).every(i=>i==="key"||i==="instanceIndex"||i==="instanceCount")}function le(t){return h(t)&&typeof t.id=="string"&&typeof t.siteId=="string"&&typeof t.baseSnapshotId=="string"&&x(t.composition)&&typeof t.kind=="string"&&h(t.target)&&(t.target.kind!=="route"||x(t.target.composition))&&typeof t.documentVersion=="number"&&Number.isInteger(t.documentVersion)&&t.documentVersion>=0&&h(t.params)}function x(t){return h(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 fe(t){return h(t)&&typeof t.routeId=="string"&&(t.effectiveTemplateId===void 0||typeof t.effectiveTemplateId=="string")}function H(t){if(x(t.composition))return t.composition;throw new C(N,"A composition selector is required for this request.")}function me(t){if(h(t)&&x(t.composition))return t.composition;throw new C(N,"A composition selector is required for execute.")}function Q(t){return{routeId:t.routeId,...t.effectiveTemplateId?{templateId:t.effectiveTemplateId}:{}}}function ge(t){return t.activeComposition?w(t.activeComposition):null}function w(t){return JSON.stringify([t.routeId,t.effectiveTemplateId??null])}function I(t,e){return h(t)&&t.ok===!0?{...t,composition:e}:t}function ye(t,e){return!h(t)||t.ok!==!0?t:{...t,...e?{composition:e}:{},data:G(t.data)}}function G(t){let e=t;return L(e.routeId?e:{...e,routeId:e.composition.routeId})}function h(t){return typeof t=="object"&&t!==null}function M(t){return h(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 D(t){if(!(!h(t)||typeof t.code!="string"||t.code.length===0))return t.code}function K(t){return t instanceof Error||h(t)&&typeof t.message=="string"&&t.message.length>0?t.message:"Unknown websocket operation failure"}function Ie(t){try{return m.extractRequestInfo(JSON.parse(t))}catch{return{id:"unknown",kind:"get-document"}}}var O=class{constructor(){this.tail=Promise.resolve()}run(e){let n=this.tail.then(e,e);return this.tail=n.then(()=>{},()=>{}),n}};import{SiteEditOperationRequestSchema as Te,computeSiteEditCompositionKey as E}from"@vcp-dev/contracts";var Oe="127.0.0.1",Ae=30218,He="/__vcp/site-edit/bridge",se=6*1024*1024,Me=se*2,De=3e3,Y=50,V=".vcp/current-snapshot.json",Z="__VCP_SITE_EDIT_BRIDGE_SERVERS__";function ut(t){let e=A(t),n=re(e),i=oe(),o=i.get(n);if(o)return o;let s=new k(e);i.set(n,s);try{s.start()}catch(r){throw i.delete(n),s.stop(),r}return s}function dt(t,e,n={}){let i=new k(A(e),t,!1,n);return i.start({listen:!1}),i}var k=class{constructor(e,n=te.createServer((s,r)=>{r.writeHead(404),r.end("VCP site edit bridge server")}),i=!0,o={}){this.options=e,this.server=n,this.closeHttpServerOnStop=i,this.dependencies=o,this.runtime=null,this.activeHistorySessionId=null,this.historySessionTransition=Promise.resolve(),this.mutationQueue=new O,this.eventListeners=new Set,this.routes=[],this.compositions=[],this.compositionFiles=[],this.compositionResolutionError=null,this.launchCandidateEntries=null,this.stopWatching=null,this.stopWebSocketServer=null,this.pendingChangedFiles=new Set,this.fileChangeTimer=null,this.isStarted=!1,this.stopping=!1,this.runtimeVersionFloors=new Map,this.activeHistoryStore=null,this.versionPersistence=Promise.resolve(),this.bridgeEngine=null,this.lastNotifiedHealth=null}start(e={}){if(!this.isStarted){this.stopping=!1;try{v.mkdirSync(g.join(this.options.projectRoot,".vcp"),{recursive:!0})}catch(n){console.warn(`[vcp-site-edit] failed to ensure .vcp directory: ${n instanceof Error?n.message:String(n)}`)}if(this.refreshCompositions(!0),this.isStarted=!0,this.createRuntime(),this.bridgeEngine=this.createBridgeEngine(),e.webSocket!==!1){let n=Pe({server:this.server,path:this.options.path,sessionKey:this.options.sessionKey,host:this.options.host,allowedOrigins:this.options.allowedOrigins,engine:this.bridgeEngine});this.stopWebSocketServer=n.stop}this.stopWatching=new _e({projectRoot:this.options.projectRoot,watch_dirs:Ke(this.options.runtime.watch_dirs),interval_ms:this.options.runtime.watch_interval_ms,debounce_ms:this.options.runtime.watch_debounce_ms??Y,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),this.notifyHealthChanged()}}getEngine(){if(!this.bridgeEngine)throw new Error("VCP site edit preview bridge runtime is not ready");return this.bridgeEngine}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.stopping=!0,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=oe(),n=re(this.options);e.get(n)===this&&e.delete(n),this.isStarted=!1,this.notifyHealthChanged()}notifyHealthChanged(){let e=this.options.onHealthChanged;if(!e)return;let n=this.getHealth(),i=JSON.stringify(n);if(i!==this.lastNotifiedHealth){this.lastNotifiedHealth=i;try{e(n)}catch(o){console.warn(`[vcp-site-edit] onHealthChanged callback failed: ${o instanceof Error?o.message:String(o)}`)}}}createRuntime(e,n=null){let i=this.runtime;this.activeHistoryStore=e??null;let o=(this.dependencies.createRuntime??Ee)({...this.options.tenantId?{tenantId:this.options.tenantId}:{},siteId:this.options.siteId,snapshotId:this.options.snapshotId,projectRoot:this.options.projectRoot,compositions:this.compositions,onEvent:s=>{"version"in s&&typeof s.version=="number"&&this.recordRuntimeVersion(s.version,"composition"in s?s.composition:void 0);for(let r of this.eventListeners)r(s)},...e?{historyStore:e}:{},...this.getInitialDocumentVersions().length>0?{initialDocumentVersions:this.getInitialDocumentVersions()}:{}});this.runtime=o,this.activeHistorySessionId=n,i?.dispose(),this.notifyHealthChanged()}createBridgeEngine(){return{resolveComposition:e=>this.resolveComposition(e),initializeSession:e=>this.mutationQueue.run(async()=>{let n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)throw new Error(`${n.code}: ${n.message}`);let i=Be(e.composition),o=this.getRuntime(),s=y(i);await o.initializeComposition(s);let c=o.getDocument(s).data;await this.recordRuntimeVersion(c.version,i);let p=(await o.getHistoryStatus()).data;return{ok:!0,composition:i,data:{document:c,historyStatus:p}}}),getDocument:async e=>{let n=this.getRuntime(),i=y(e);await n.initializeComposition(i);let o=n.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(y(e)),getObjectEditContext:async(e,n,i)=>this.getRuntime().getObjectEditContext(e,y(n),i),getClassNameSource:async(e,n)=>this.getRuntime().getClassNameSource(e,y(n)),getSourceTree:async e=>this.getRuntime().getSourceTree(y(e)),getSourceFile:async e=>this.getRuntime().getSourceFile({path:e.path,composition:y(e.composition)}),resolveSourceLocation:async e=>this.getRuntime().resolveSourceLocation({key:e.key,composition:y(e.composition)}),execute:(e,n)=>this.mutationQueue.run(async()=>{let i=await this.bindHistorySession(this.options.snapshotId);if(!i.ok)return P(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 n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)return P(n,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 n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)return P(n,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 n=this.historySessionTransition.then(async()=>{if(this.activeHistorySessionId===e)return;let i=await(this.dependencies.openHistoryStore??Re)(Ne({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,s=this.compositions[0]?.context;if(s){let r=E(s);this.runtimeVersionFloors.set(r,Math.max(this.runtimeVersionFloors.get(r)??0,o))}this.createRuntime(i,e)});this.historySessionTransition=n.catch(()=>{});try{return await n,{ok:!0}}catch{return{ok:!1,code:"RECOVERY_PERSIST_FAILED",message:"Durable edit history could not be opened."}}}recordRuntimeVersion(e,n){let i=n?E(n):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 s=i?this.runtimeVersionFloors.get(i)??e:e;return this.versionPersistence=this.versionPersistence.then(()=>o.writeDocumentVersion(s)).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 n=this.options.runtime.watch_debounce_ms??Y;this.fileChangeTimer=setTimeout(()=>{this.fileChangeTimer=null,this.flushChangedFiles()},n),this.fileChangeTimer?.unref?.()}flushChangedFiles(){if(this.fileChangeTimer&&(clearTimeout(this.fileChangeTimer),this.fileChangeTimer=null),this.pendingChangedFiles.size===0)return;let e=[...this.pendingChangedFiles].sort((n,i)=>n.localeCompare(i));if(this.pendingChangedFiles.clear(),e.some(Le)&&this.scheduleSnapshotIdentityAdvance(),!!this.refreshCompositions(!1))for(let n of e)this.runtime?.notifyFileChanged(n)}scheduleSnapshotIdentityAdvance(){if(this.stopping||!this.isStarted)return;let e=this.readCurrentSnapshotMarker();!e||e===this.options.snapshotId||this.mutationQueue.run(()=>this.advanceSnapshotId(e)).catch(n=>{console.warn(`[vcp-site-edit] snapshot identity advance failed: ${n instanceof Error?n.message:String(n)}`)})}readCurrentSnapshotMarker(){try{let e=v.readFileSync(g.join(this.options.projectRoot,V),"utf8"),n=JSON.parse(e),i=typeof n.snapshot_id=="string"?n.snapshot_id:"";return!i||U(i)!==i?(console.warn("[vcp-site-edit] current-snapshot marker has no valid snapshot_id"),null):i}catch(e){return console.warn(`[vcp-site-edit] current-snapshot marker unreadable: ${e instanceof Error?e.message:String(e)}`),null}}async advanceSnapshotId(e){if(this.stopping||!this.isStarted||e===this.options.snapshotId)return;let n=this.options.snapshotId;this.options.snapshotId=e;try{if(this.options.historyRoot){let o=await this.bindHistorySession(e);if(!o.ok)throw new Error(`${o.code}: ${o.message}`)}else this.createRuntime()}catch(o){this.options.snapshotId=n,console.warn(`[vcp-site-edit] snapshot identity advance rolled back to ${n}: ${o instanceof Error?o.message:String(o)}`);return}let i=new Date().toISOString();for(let o of this.compositions){let s={type:"site-edit.snapshot.changed",siteId:this.options.siteId,composition:o.context,snapshotId:e,previousSnapshotId:n,at:i};for(let r of this.eventListeners)try{r(s)}catch(c){console.warn(`[vcp-site-edit] snapshot.changed listener failed: ${c instanceof Error?c.message:String(c)}`)}}try{this.options.onSnapshotIdChanged?.(e,n)}catch(o){console.warn(`[vcp-site-edit] onSnapshotIdChanged callback failed: ${o instanceof Error?o.message:String(o)}`)}}refreshCompositions(e=!1){try{let n=Fe(this.options.projectRoot),i=ke(n),o=i.length>0?i:(this.options.runtime.routes??[]).map(u=>({...u})),s=xe({files:n});if(s.length===0)throw new Error("No canonical App Router composition is indexed by the preview bridge.");let r=JSON.stringify(s.filter(u=>u.context.effectiveTemplateId!==void 0).map(u=>u.entryFile).sort());if(e&&(this.launchCandidateEntries=r),this.launchCandidateEntries!==r)throw new Error("SITE_EDIT_RUNTIME_RELOAD_REQUIRED: Candidate route collection changed since preview launch");let c=new Map(this.compositions.map(u=>[E(u.context),u])),p=new Map(s.map(u=>[E(u.context),u]));if(this.runtime){for(let[u,l]of c){let S=p.get(u);(!S||S.entryFile!==l.entryFile)&&this.runtime.unregisterComposition(y(l.context))}for(let[u,l]of p){let S=c.get(u);(!S||S.entryFile!==l.entryFile)&&this.runtime.registerComposition(l.context,l.entryFile)}}return this.routes=o,this.compositions=s,this.compositionFiles=n,this.compositionResolutionError=null,this.notifyHealthChanged(),!0}catch(n){let i=n instanceof Error?n:new Error(String(n));if(this.compositionResolutionError=i,e)throw i;return this.notifyHealthChanged(),!1}}resolveComposition(e){if(this.compositionResolutionError)throw this.compositionResolutionError;let n=ve(e.routeId,this.routes,this.options.basePath);if(!n)throw new Error(`Route is not indexed by the preview bridge: ${e.routeId}`);let i=this.routes.find(r=>r.routeId===n);if(!i)throw new Error(`Route is not indexed by the preview bridge: ${e.routeId}`);let o=be({selector:{routeId:n,...e.templateId!==void 0?{templateId:e.templateId}:{}},files:this.compositionFiles,canonicalEntryFile:i.entryFile}),s=E(o.context);if(!this.compositions.some(r=>E(r.context)===s))throw new Error(`Composition is not registered by the preview bridge: ${s}`);return o}getInitialDocumentVersions(){return this.compositions.flatMap(e=>{let n=this.runtimeVersionFloors.get(E(e.context));return n===void 0?[]:[{composition:e.context,version:n}]})}getRuntime(){if(!this.runtime)throw new Error("VCP site edit preview bridge runtime is not ready");return this.runtime}};function ht(t){let e=new k(A(t),te.createServer(),!1);return e.start({listen:!1,webSocket:!1}),{engine:e.getEngine(),getHealth:()=>e.getHealth(),stop:()=>e.stop()}}function pt(t){return A(t)}function A(t){return{tenantId:t.tenantId,siteId:t.siteId,snapshotId:t.snapshotId,projectRoot:g.resolve(t.projectRoot??process.cwd()),basePath:t.basePath??"",host:t.host??Oe,port:t.port??Ae,path:t.path??He,sessionKey:t.sessionKey??ze(),historyRoot:t.historyRoot,allowedOrigins:t.allowedOrigins??[],runtime:t.runtime??{},onSnapshotIdChanged:t.onSnapshotIdChanged,onHealthChanged:t.onHealthChanged}}function Ke(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 Fe(t){let e=[],n=["app","src/app",".vcp"],i=new Set([".git",".next",".turbo","coverage","dist","node_modules","output","snapshot-store"]),o=s=>{if(!v.existsSync(s))return;let r;try{r=v.readdirSync(s,{withFileTypes:!0})}catch{return}for(let c of r){if(c.name.startsWith(".")&&c.name!==".vcp")continue;if(c.isDirectory()){if(i.has(c.name))continue;o(g.join(s,c.name));continue}if(!c.isFile())continue;let p=g.join(s,c.name),u="";try{u=v.readFileSync(p,"utf8")}catch{}e.push({path:g.relative(t,p).replaceAll(g.sep,"/"),content:u})}};for(let s of n)o(g.join(t,s));return e.sort((s,r)=>s.path.localeCompare(r.path))}function Be(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 y(t){return{routeId:t.routeId,...t.effectiveTemplateId?{templateId:t.effectiveTemplateId}:{}}}function Ne(t){return g.join(g.resolve(t.root),U(t.siteId),U(t.snapshotId),ne("sha256").update(t.editingSessionId).digest("hex").slice(0,32))}function U(t){return/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(t)&&t!=="."&&t!==".."?t:ne("sha256").update(t).digest("hex").slice(0,32)}function oe(){let t=globalThis;return t[Z]??=new Map,t[Z]}function re(t){return`${t.projectRoot}:${t.host}:${t.port}:${t.path}:${t.historyRoot??""}`}function P(t,e,n){let i=n??(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 Pe(t){let e=new Ce({maxPayload:se,noServer:!0}),n=new WeakSet,i=s=>{new T({socket:new W(s),engine:t.engine,validateOperationRequest:r=>Te.safeParse(r).success})},o=(s,r,c)=>{if(!qe(s,t))return;let p=Ve(s,t);if(!p){r.write(`HTTP/1.1 401 Unauthorized\r
1
+ import ne from"node:http";import v from"node:fs";import{createHash as j,randomBytes as Se,timingSafeEqual as we}from"node:crypto";import m from"node:path";import{WebSocket as ie,WebSocketServer as Ce}from"ws";import{createPreviewSiteEditEngineRuntime as Ee,openFileHistoryStore as Re,resolveManagedPageTemplateComposition as be,scanSiteEditCompositionsFromFiles as xe}from"@vcp-dev/site-edit-engine";import{resolveNextAppRouteId as ve,scanNextAppRouterRoutesFromFiles as ke}from"@vcp-dev/site-edit-engine/next-app-router";import{SiteEditSourceWatcher as _e}from"@vcp-dev/site-edit-engine/source-watcher";function J(t){let e=new Map,n=[],i=new Map,o=[],s=t.pageComposition.status==="supported"?t.pageComposition.placementUnitKeys:[],r=new Map(s.map((c,d)=>[c,d])),a=t.pageComposition.status==="supported"?{status:"supported",containerKey:t.pageComposition.containerKey,hasBusinessMembers:t.pageComposition.hasBusinessMembers,placementUnitKeys:t.pageComposition.placementUnitKeys,placements:t.pageComposition.placements.map(c=>({placementKey:c.placementKey,placementUnitKey:c.placementUnitKey,relation:c.relation}))}:{status:"unsupported",reason:t.pageComposition.reason,diagnostics:t.pageComposition.diagnostics},p=t.entries.flatMap((c,d)=>c.dynamicDataSummary?[[d,c.dynamicDataSummary]]:[]),u=new Map(t.entries.map((c,d)=>[c.key,d])),l=[];for(let[c,d]of t.entries.entries()){let f=d.pageCompositionActionScope;if(!f)continue;if(f.kind!=="source-siblings"){l.push([c,{kind:f.kind}]);continue}let _=f.siblingKeys.map(R=>{let b=u.get(R);if(b===void 0)throw new Error("Render entry "+d.key+" references missing source sibling "+R);return b});l.push([c,{kind:"source-siblings",siblingEntryIndexes:_}])}let S=c=>{let d=e.get(c);if(typeof d=="number")return d;let f=n.length;return n.push(c),e.set(c,f),f},z=c=>{let d=null;for(let f of de(c)){let _=`${d??"root"}\0${f}`,R=i.get(_);if(typeof R=="number"){d=R;continue}let b=o.length;o.push([d,S(f)]),i.set(_,b),d=b}if(d===null)throw new Error("Document key must not be empty");return d};return{encoding:"segment-trie-v1",siteId:t.siteId,snapshotId:t.snapshotId,composition:{...t.composition},routeId:t.composition.routeId,version:t.version,pageComposition:a,tokens:n,nodes:o,entries:t.entries.map(c=>{let d=c.pageCompositionUnitKey?r.get(c.pageCompositionUnitKey)??-1:-1;if(c.pageCompositionUnitKey&&d<0)throw new Error(`Render entry ${c.key} references unknown page composition unit ${c.pageCompositionUnitKey}`);return[z(c.key),ue(c.operationSummary),...d>=0?[d]:[]]}),...l.length>0?{pageCompositionActionScopes:l}:{},...t.entries.every(c=>c.parentKey!==void 0)?{entryParentNodeIds:t.entries.map(c=>c.parentKey===null?null:z(c.parentKey))}:{},...p.length>0?{dynamicDataSummaries:p}:{}}}function ue(t){return(t.canUpdateText?1:0)|(t.canInsertChild?2:0)|(t.canMove?4:0)|(t.canRemove?8:0)}function de(t){if(!t)return[];let e=[],n=0,i=L(t,n);if(i<0)return e.push(t),e;for(e.push(t.slice(0,i)),n=i;n<t.length;){if(i=L(t,n+(t.startsWith("::",n)?2:1)),i<0){e.push(t.slice(n));break}e.push(t.slice(n,i)),n=i}return e}function L(t,e){let n=t.indexOf("/",e),i=t.indexOf("::",e);return n<0?i:i<0?n:Math.min(n,i)}var Q="SITE_EDIT_COMPOSITION_SESSION_MISMATCH",N="SITE_EDIT_COMPOSITION_SESSION_REQUIRED";var g=class t{constructor(){}static parseMessage(e,n={}){let i=JSON.parse(e);if(!t.isMessage(i,n))throw new Error("Invalid site edit bridge message");return i}static stringifyMessage(e){return JSON.stringify(e)}static extractRequestInfo(e){if(h(e)&&h(e.payload)){let n=typeof e.payload.id=="string"?e.payload.id:"unknown",i=this.isRequestKind(e.payload.kind)?e.payload.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==="get-operation-result"||e==="undo"||e==="redo"}static isMessage(e,n={}){return!h(e)||typeof e.type!="string"?!1:e.type==="request"?he(e.payload,n):e.type==="response"||e.type==="error"?h(e.payload)&&typeof e.payload.id=="string":e.type==="event"?h(e.payload)&&h(e.payload.event):e.type==="auth"?h(e.payload)&&typeof e.payload.key=="string":e.type==="auth-ok"&&h(e.payload)&&e.payload.ok===!0}},T=class{constructor(e){this.options=e,this.session={subscribedCompositionKeys:new Set},this.messageQueue=new B,this.eventDispatcher=new F(n=>{this.sendJson(n)}),this.unsubscribe=e.engine.subscribe(n=>{this.handleEngineEvent(n)}),e.socket.onmessage=n=>{try{this.messageQueue.enqueue(()=>this.handleRawMessage(n.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 n=e;if(n.type!=="request")return;let i=n.payload,{id:o}=i;switch(i.kind){case"initialize-session":{let s=H(i),r=await this.resolve(s),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:I({...a,data:{...a.data,document:Y(a.data.document)}},r.context)}});return}case"get-document":{let s=await this.resolveWireContext(i),r=await this.options.engine.getDocument(s);this.sendResult(o,i.kind,ye(r,s));return}case"get-history-status":{let s=await this.resolveWireContext(i),r=await this.options.engine.getHistoryStatus(s);this.sendResult(o,i.kind,I(r,s));return}case"get-style-context":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getStyleContext(s),s));return}case"get-object-edit-context":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getObjectEditContext(i.key,s,i.selectionRef),s));return}case"get-class-name-source":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getClassNameSource(i.key,s),s));return}case"get-source-tree":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getSourceTree(s),s));return}case"get-source-file":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getSourceFile({path:i.path,composition:s}),s));return}case"resolve-source-location":{let s=await this.resolveWireContext(i),r=I(await this.options.engine.resolveSourceLocation({key:i.key,composition:s}),s);this.sendResult(o,i.kind,r);return}case"execute":case"get-operation-result":{let s=await this.resolveOperationWireContext(i.request),r=await this.resolveWireContext(i);if(w(s)!==w(r))throw new C(Q,"The execute request composition does not match its operation composition.");let a=await this.normalizeOperationRequest(i.request,s);if(i.kind==="get-operation-result"){this.sendResult(o,i.kind,await this.options.engine.getOperationResult?.(a)??null);return}await this.handleBufferedOperation(o,i.kind,()=>this.options.engine.execute(a));return}case"undo":case"redo":{let s=await this.resolveWireContext(i);await this.handleBufferedOperation(o,i.kind,()=>i.kind==="undo"?this.options.engine.undo(s):this.options.engine.redo(s));return}}}catch(n){let i=g.extractRequestInfo(e);this.sendJson({type:"error",payload:{...i,message:K(n),code:D(n)}})}}async resolve(e){return this.options.engine.resolveComposition(e)}async resolveAndAssert(e){let n=await this.resolve(e),i=this.session.activeComposition;if(!i)throw new C(N,"Initialize a composition session before issuing this request.");if(w(i)!==w(n.context))throw new C(Q,"The request composition does not match the active socket session.");return n.context}async resolveWireContext(e){let n=H(e);return this.resolveAndAssert(n)}async resolveOperationWireContext(e){let n=ge(e);return this.resolveAndAssert(n)}activateSession(e){this.session.activeComposition=e,this.session.subscribedCompositionKeys.clear(),this.session.subscribedCompositionKeys.add(w(e))}async normalizeOperationRequest(e,n){let i={...e,composition:G(n)};if(i.target.kind==="route"){let o=i.target,s=H(o),r=await this.resolveAndAssert(s);i.target={...o,composition:G(r)}}return i}handleEngineEvent(e){let n=e?.composition;if(!fe(n))return;let i=w(n);this.session.subscribedCompositionKeys.has(i)&&(this.eventDispatcher.push(e),e.type==="site-edit.graph.invalidated"&&i===me(this.session)&&(this.session.activeComposition=void 0,this.session.subscribedCompositionKeys.delete(i)))}sendResult(e,n,i){this.sendJson({type:"response",payload:{id:e,kind:n,result:i}})}async handleRawMessage(e){try{await this.handleMessage(g.parseMessage(e,{validateOperationRequest:this.options.validateOperationRequest}))}catch(n){let i=Ie(e);this.sendJson({type:"error",payload:{...i,message:K(n),code:D(n)}})}}sendJson(e){this.options.socket.send(g.stringifyMessage(e))}async handleBufferedOperation(e,n,i){this.eventDispatcher.beginBuffering();try{let o=await i();this.sendResult(e,n,o)}catch(o){this.sendJson({type:"error",payload:{id:e,kind:n,message:K(o),code:D(o)}})}finally{this.eventDispatcher.flush()}}},C=class extends Error{constructor(e,n){super(n),this.code=e,this.name="BridgeProtocolError"}},F=class{constructor(e){this.send=e,this.bufferedEvents=null}push(e){let n={type:"event",payload:{event:e}};if(this.bufferedEvents){this.bufferedEvents.push(n);return}this.send(n)}beginBuffering(){this.bufferedEvents=[]}flush(){let e=this.bufferedEvents??[];this.bufferedEvents=null,e.forEach(n=>this.send(n))}},B=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 n=async()=>{this.queued-=1,await e()},i=this.queue.then(n,n);return this.queue=i.then(()=>{},()=>{}),i}};function he(t,e){if(!h(t)||typeof t.id!="string"||!g.isRequestKind(t.kind))return!1;let n=x(t.composition);switch(t.kind){case"initialize-session":return n&&(t.mutationContext===void 0||M(t.mutationContext));case"get-document":case"get-style-context":return n;case"get-object-edit-context":return typeof t.key=="string"&&n&&pe(t.selectionRef);case"get-class-name-source":case"resolve-source-location":return typeof t.key=="string"&&n;case"get-history-status":return n;case"get-source-tree":return n;case"get-source-file":return typeof t.path=="string"&&n;case"execute":case"get-operation-result":return n&&le(t.request)&&(t.request.mutationContext===void 0||M(t.request.mutationContext))&&(e.validateOperationRequest?.(t.request)??!0);case"undo":case"redo":return n&&t.mutationContext===void 0||n&&M(t.mutationContext)}}function pe(t){if(t===void 0)return!0;if(!h(t)||typeof t.key!="string"||t.key.length===0)return!1;let e=t.instanceIndex,n=t.instanceCount;return e!==void 0&&(typeof e!="number"||!Number.isInteger(e)||e<0)||n!==void 0&&(typeof n!="number"||!Number.isInteger(n)||n<=0)||typeof e=="number"&&typeof n=="number"&&e>=n?!1:Object.keys(t).every(i=>i==="key"||i==="instanceIndex"||i==="instanceCount")}function le(t){return h(t)&&typeof t.id=="string"&&typeof t.siteId=="string"&&typeof t.baseSnapshotId=="string"&&x(t.composition)&&typeof t.kind=="string"&&h(t.target)&&(t.target.kind!=="route"||x(t.target.composition))&&typeof t.documentVersion=="number"&&Number.isInteger(t.documentVersion)&&t.documentVersion>=0&&h(t.params)}function x(t){return h(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 fe(t){return h(t)&&typeof t.routeId=="string"&&(t.effectiveTemplateId===void 0||typeof t.effectiveTemplateId=="string")}function H(t){if(x(t.composition))return t.composition;throw new C(N,"A composition selector is required for this request.")}function ge(t){if(h(t)&&x(t.composition))return t.composition;throw new C(N,"A composition selector is required for execute.")}function G(t){return{routeId:t.routeId,...t.effectiveTemplateId?{templateId:t.effectiveTemplateId}:{}}}function me(t){return t.activeComposition?w(t.activeComposition):null}function w(t){return JSON.stringify([t.routeId,t.effectiveTemplateId??null])}function I(t,e){return h(t)&&t.ok===!0?{...t,composition:e}:t}function ye(t,e){return!h(t)||t.ok!==!0?t:{...t,...e?{composition:e}:{},data:Y(t.data)}}function Y(t){let e=t;return J(e.routeId?e:{...e,routeId:e.composition.routeId})}function h(t){return typeof t=="object"&&t!==null}function M(t){return h(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 D(t){if(!(!h(t)||typeof t.code!="string"||t.code.length===0))return t.code}function K(t){return t instanceof Error||h(t)&&typeof t.message=="string"&&t.message.length>0?t.message:"Unknown websocket operation failure"}function Ie(t){try{return g.extractRequestInfo(JSON.parse(t))}catch{return{id:"unknown",kind:"get-document"}}}var O=class{constructor(){this.tail=Promise.resolve()}run(e){let n=this.tail.then(e,e);return this.tail=n.then(()=>{},()=>{}),n}};import{SiteEditOperationRequestSchema as Te,computeSiteEditCompositionKey as E}from"@vcp-dev/contracts";var Oe="127.0.0.1",Ae=30218,He="/__vcp/site-edit/bridge",se=6*1024*1024,Me=se*2,De=3e3,Z=50,U=".vcp/current-snapshot.json",X="__VCP_SITE_EDIT_BRIDGE_SERVERS__";function ut(t){let e=A(t),n=re(e),i=oe(),o=i.get(n);if(o)return o;let s=new k(e);i.set(n,s);try{s.start()}catch(r){throw i.delete(n),s.stop(),r}return s}function dt(t,e,n={}){let i=new k(A(e),t,!1,n);return i.start({listen:!1}),i}var k=class{constructor(e,n=ne.createServer((s,r)=>{r.writeHead(404),r.end("VCP site edit bridge server")}),i=!0,o={}){this.options=e,this.server=n,this.closeHttpServerOnStop=i,this.dependencies=o,this.runtime=null,this.activeHistorySessionId=null,this.historySessionTransition=Promise.resolve(),this.mutationQueue=new O,this.operationReceipts=new Map,this.eventListeners=new Set,this.routes=[],this.compositions=[],this.compositionFiles=[],this.compositionResolutionError=null,this.launchCandidateEntries=null,this.stopWatching=null,this.stopWebSocketServer=null,this.pendingChangedFiles=new Set,this.fileChangeTimer=null,this.isStarted=!1,this.stopping=!1,this.runtimeVersionFloors=new Map,this.activeHistoryStore=null,this.versionPersistence=Promise.resolve(),this.bridgeEngine=null,this.lastNotifiedHealth=null}start(e={}){if(!this.isStarted){this.stopping=!1;try{v.mkdirSync(m.join(this.options.projectRoot,".vcp"),{recursive:!0})}catch(n){console.warn(`[vcp-site-edit] failed to ensure .vcp directory: ${n instanceof Error?n.message:String(n)}`)}if(this.refreshCompositions(!0),this.isStarted=!0,this.createRuntime(),this.bridgeEngine=this.createBridgeEngine(),e.webSocket!==!1){let n=Pe({server:this.server,path:this.options.path,sessionKey:this.options.sessionKey,host:this.options.host,allowedOrigins:this.options.allowedOrigins,engine:this.bridgeEngine});this.stopWebSocketServer=n.stop}this.stopWatching=new _e({projectRoot:this.options.projectRoot,watch_dirs:Ke(this.options.runtime.watch_dirs),interval_ms:this.options.runtime.watch_interval_ms,debounce_ms:this.options.runtime.watch_debounce_ms??Z,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),this.notifyHealthChanged()}}getEngine(){if(!this.bridgeEngine)throw new Error("VCP site edit preview bridge runtime is not ready");return this.bridgeEngine}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.stopping=!0,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=oe(),n=re(this.options);e.get(n)===this&&e.delete(n),this.isStarted=!1,this.notifyHealthChanged()}notifyHealthChanged(){let e=this.options.onHealthChanged;if(!e)return;let n=this.getHealth(),i=JSON.stringify(n);if(i!==this.lastNotifiedHealth){this.lastNotifiedHealth=i;try{e(n)}catch(o){console.warn(`[vcp-site-edit] onHealthChanged callback failed: ${o instanceof Error?o.message:String(o)}`)}}}createRuntime(e,n=null){let i=this.runtime;this.activeHistoryStore=e??null;let o=(this.dependencies.createRuntime??Ee)({...this.options.tenantId?{tenantId:this.options.tenantId}:{},siteId:this.options.siteId,snapshotId:this.options.snapshotId,projectRoot:this.options.projectRoot,compositions:this.compositions,onEvent:s=>{"version"in s&&typeof s.version=="number"&&this.recordRuntimeVersion(s.version,"composition"in s?s.composition:void 0);for(let r of this.eventListeners)r(s)},...e?{historyStore:e}:{},...this.getInitialDocumentVersions().length>0?{initialDocumentVersions:this.getInitialDocumentVersions()}:{}});this.runtime=o,this.activeHistorySessionId=n,i?.dispose(),this.notifyHealthChanged()}createBridgeEngine(){return{resolveComposition:e=>this.resolveComposition(e),initializeSession:e=>this.mutationQueue.run(async()=>{let n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)throw new Error(`${n.code}: ${n.message}`);let i=Be(e.composition),o=this.getRuntime(),s=y(i);await o.initializeComposition(s);let a=o.getDocument(s).data;await this.recordRuntimeVersion(a.version,i);let p=(await o.getHistoryStatus()).data;return{ok:!0,composition:i,data:{document:a,historyStatus:p}}}),getDocument:async e=>{let n=this.getRuntime(),i=y(e);await n.initializeComposition(i);let o=n.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(y(e)),getObjectEditContext:async(e,n,i)=>this.getRuntime().getObjectEditContext(e,y(n),i),getClassNameSource:async(e,n)=>this.getRuntime().getClassNameSource(e,y(n)),getSourceTree:async e=>this.getRuntime().getSourceTree(y(e)),getSourceFile:async e=>this.getRuntime().getSourceFile({path:e.path,composition:y(e.composition)}),resolveSourceLocation:async e=>this.getRuntime().resolveSourceLocation({key:e.key,composition:y(e.composition)}),execute:(e,n)=>this.executeWithReceipt(e,()=>this.mutationQueue.run(async()=>{let i=await this.bindHistorySession(this.options.snapshotId);if(!i.ok)return P(i,e);let o=await this.getRuntime().executeOperation(e);return o.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(o.data.resultVersion,o.composition),o})),getOperationResult:e=>{if(e.siteId!==this.options.siteId||e.baseSnapshotId!==this.options.snapshotId)return null;let n=this.operationReceipts.get(this.operationReceiptKey(e));return n?.fingerprint===this.operationFingerprint(e)?n.result:null},undo:e=>this.mutationQueue.run(async()=>{let n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)return P(n,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 n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)return P(n,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))}}operationReceiptKey(e){return JSON.stringify([e.siteId,e.baseSnapshotId,e.id])}operationFingerprint(e){return j("sha256").update(JSON.stringify(e)).digest("hex")}executeWithReceipt(e,n){if(e.siteId!==this.options.siteId||e.baseSnapshotId!==this.options.snapshotId)return n();let i=this.operationReceiptKey(e),o=this.operationFingerprint(e),s=this.operationReceipts.get(i);if(s)return s.fingerprint!==o?Promise.reject(new Error("Operation ID was reused with a different request.")):s.result;let r={fingerprint:o,result:n(),settled:!1};return this.operationReceipts.set(i,r),r.result.then(()=>{r.settled=!0;for(let[a,p]of this.operationReceipts){if(this.operationReceipts.size<=256)break;p.settled&&this.operationReceipts.delete(a)}},()=>{this.operationReceipts.delete(i)}),r.result}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 n=this.historySessionTransition.then(async()=>{if(this.activeHistorySessionId===e)return;let i=await(this.dependencies.openHistoryStore??Re)(Ne({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,s=this.compositions[0]?.context;if(s){let r=E(s);this.runtimeVersionFloors.set(r,Math.max(this.runtimeVersionFloors.get(r)??0,o))}this.createRuntime(i,e)});this.historySessionTransition=n.catch(()=>{});try{return await n,{ok:!0}}catch{return{ok:!1,code:"RECOVERY_PERSIST_FAILED",message:"Durable edit history could not be opened."}}}recordRuntimeVersion(e,n){let i=n?E(n):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 s=i?this.runtimeVersionFloors.get(i)??e:e;return this.versionPersistence=this.versionPersistence.then(()=>o.writeDocumentVersion(s)).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 n=this.options.runtime.watch_debounce_ms??Z;this.fileChangeTimer=setTimeout(()=>{this.fileChangeTimer=null,this.flushChangedFiles()},n),this.fileChangeTimer?.unref?.()}flushChangedFiles(){if(this.fileChangeTimer&&(clearTimeout(this.fileChangeTimer),this.fileChangeTimer=null),this.pendingChangedFiles.size===0)return;let e=[...this.pendingChangedFiles].sort((n,i)=>n.localeCompare(i));if(this.pendingChangedFiles.clear(),e.some(Le)&&this.scheduleSnapshotIdentityAdvance(),!!this.refreshCompositions(!1))for(let n of e)this.runtime?.notifyFileChanged(n)}scheduleSnapshotIdentityAdvance(){if(this.stopping||!this.isStarted)return;let e=this.readCurrentSnapshotMarker();!e||e===this.options.snapshotId||this.mutationQueue.run(()=>this.advanceSnapshotId(e)).catch(n=>{console.warn(`[vcp-site-edit] snapshot identity advance failed: ${n instanceof Error?n.message:String(n)}`)})}readCurrentSnapshotMarker(){try{let e=v.readFileSync(m.join(this.options.projectRoot,U),"utf8"),n=JSON.parse(e),i=typeof n.snapshot_id=="string"?n.snapshot_id:"";return!i||q(i)!==i?(console.warn("[vcp-site-edit] current-snapshot marker has no valid snapshot_id"),null):i}catch(e){return console.warn(`[vcp-site-edit] current-snapshot marker unreadable: ${e instanceof Error?e.message:String(e)}`),null}}async advanceSnapshotId(e){if(this.stopping||!this.isStarted||e===this.options.snapshotId)return;let n=this.options.snapshotId;this.options.snapshotId=e;try{if(this.options.historyRoot){let o=await this.bindHistorySession(e);if(!o.ok)throw new Error(`${o.code}: ${o.message}`)}else this.createRuntime()}catch(o){this.options.snapshotId=n,console.warn(`[vcp-site-edit] snapshot identity advance rolled back to ${n}: ${o instanceof Error?o.message:String(o)}`);return}let i=new Date().toISOString();for(let o of this.compositions){let s={type:"site-edit.snapshot.changed",siteId:this.options.siteId,composition:o.context,snapshotId:e,previousSnapshotId:n,at:i};for(let r of this.eventListeners)try{r(s)}catch(a){console.warn(`[vcp-site-edit] snapshot.changed listener failed: ${a instanceof Error?a.message:String(a)}`)}}try{this.options.onSnapshotIdChanged?.(e,n)}catch(o){console.warn(`[vcp-site-edit] onSnapshotIdChanged callback failed: ${o instanceof Error?o.message:String(o)}`)}}refreshCompositions(e=!1){try{let n=Fe(this.options.projectRoot),i=ke(n),o=i.length>0?i:(this.options.runtime.routes??[]).map(u=>({...u})),s=xe({files:n});if(s.length===0)throw new Error("No canonical App Router composition is indexed by the preview bridge.");let r=JSON.stringify(s.filter(u=>u.context.effectiveTemplateId!==void 0).map(u=>u.entryFile).sort());if(e&&(this.launchCandidateEntries=r),this.launchCandidateEntries!==r)throw new Error("SITE_EDIT_RUNTIME_RELOAD_REQUIRED: Candidate route collection changed since preview launch");let a=new Map(this.compositions.map(u=>[E(u.context),u])),p=new Map(s.map(u=>[E(u.context),u]));if(this.runtime){for(let[u,l]of a){let S=p.get(u);(!S||S.entryFile!==l.entryFile)&&this.runtime.unregisterComposition(y(l.context))}for(let[u,l]of p){let S=a.get(u);(!S||S.entryFile!==l.entryFile)&&this.runtime.registerComposition(l.context,l.entryFile)}}return this.routes=o,this.compositions=s,this.compositionFiles=n,this.compositionResolutionError=null,this.notifyHealthChanged(),!0}catch(n){let i=n instanceof Error?n:new Error(String(n));if(this.compositionResolutionError=i,e)throw i;return this.notifyHealthChanged(),!1}}resolveComposition(e){if(this.compositionResolutionError)throw this.compositionResolutionError;let n=ve(e.routeId,this.routes,this.options.basePath);if(!n)throw new Error(`Route is not indexed by the preview bridge: ${e.routeId}`);let i=this.routes.find(r=>r.routeId===n);if(!i)throw new Error(`Route is not indexed by the preview bridge: ${e.routeId}`);let o=be({selector:{routeId:n,...e.templateId!==void 0?{templateId:e.templateId}:{}},files:this.compositionFiles,canonicalEntryFile:i.entryFile}),s=E(o.context);if(!this.compositions.some(r=>E(r.context)===s))throw new Error(`Composition is not registered by the preview bridge: ${s}`);return o}getInitialDocumentVersions(){return this.compositions.flatMap(e=>{let n=this.runtimeVersionFloors.get(E(e.context));return n===void 0?[]:[{composition:e.context,version:n}]})}getRuntime(){if(!this.runtime)throw new Error("VCP site edit preview bridge runtime is not ready");return this.runtime}};function ht(t){let e=new k(A(t),ne.createServer(),!1);return e.start({listen:!1,webSocket:!1}),{engine:e.getEngine(),getHealth:()=>e.getHealth(),stop:()=>e.stop()}}function pt(t){return A(t)}function A(t){return{tenantId:t.tenantId,siteId:t.siteId,snapshotId:t.snapshotId,projectRoot:m.resolve(t.projectRoot??process.cwd()),basePath:t.basePath??"",host:t.host??Oe,port:t.port??Ae,path:t.path??He,sessionKey:t.sessionKey??ze(),historyRoot:t.historyRoot,allowedOrigins:t.allowedOrigins??[],runtime:t.runtime??{},onSnapshotIdChanged:t.onSnapshotIdChanged,onHealthChanged:t.onHealthChanged}}function Ke(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 Fe(t){let e=[],n=["app","src/app",".vcp"],i=new Set([".git",".next",".turbo","coverage","dist","node_modules","output","snapshot-store"]),o=s=>{if(!v.existsSync(s))return;let r;try{r=v.readdirSync(s,{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(m.join(s,a.name));continue}if(!a.isFile())continue;let p=m.join(s,a.name),u="";try{u=v.readFileSync(p,"utf8")}catch{}e.push({path:m.relative(t,p).replaceAll(m.sep,"/"),content:u})}};for(let s of n)o(m.join(t,s));return e.sort((s,r)=>s.path.localeCompare(r.path))}function Be(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 y(t){return{routeId:t.routeId,...t.effectiveTemplateId?{templateId:t.effectiveTemplateId}:{}}}function Ne(t){return m.join(m.resolve(t.root),q(t.siteId),q(t.snapshotId),j("sha256").update(t.editingSessionId).digest("hex").slice(0,32))}function q(t){return/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(t)&&t!=="."&&t!==".."?t:j("sha256").update(t).digest("hex").slice(0,32)}function oe(){let t=globalThis;return t[X]??=new Map,t[X]}function re(t){return`${t.projectRoot}:${t.host}:${t.port}:${t.path}:${t.historyRoot??""}`}function P(t,e,n){let i=n??(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 Pe(t){let e=new Ce({maxPayload:se,noServer:!0}),n=new WeakSet,i=s=>{new T({socket:new W(s),engine:t.engine,validateOperationRequest:r=>Te.safeParse(r).success})},o=(s,r,a)=>{if(!Ve(s,t))return;let p=Ue(s,t);if(!p){r.write(`HTTP/1.1 401 Unauthorized\r
2
2
  Connection: close\r
3
3
  \r
4
- `),r.destroy();return}p.authenticatedByHeader&&n.add(s),e.handleUpgrade(s,r,c,u=>{e.emit("connection",u,s)})};return t.server.on("upgrade",o),e.on("connection",(s,r)=>{if(n.has(r)){i(s);return}Ue(s,t.sessionKey,()=>{i(s)})}),e.stop=()=>{t.server.off("upgrade",o);for(let s of e.clients)s.close(1001,"bridge stopped");e.close()},e}var W=class{constructor(e){this.socket=e,this.onmessage=null,this.onclose=null,e.on("error",()=>{}),e.on("message",n=>{this.onmessage?.({data:n.toString()})}),e.on("close",()=>{this.onclose?.()})}send(e){if(this.socket.readyState===ie.OPEN){if(this.socket.bufferedAmount+Buffer.byteLength(e,"utf8")>Me){this.socket.close(1013,"bridge backpressure");return}this.socket.send(e)}}close(e,n){this.socket.close(e,n)}};function qe(t,e){return new URL(t.url??"/","http://localhost").pathname===e.path}function Ve(t,e){if(new URL(t.url??"/","http://localhost").searchParams.has("vcp_bridge_key"))return null;let i=q(t.headers["x-vcp-site-edit-key"]),o=ae(i,e.sessionKey),s=q(t.headers.host),r=q(t.headers.origin);return s&&!We(s,e.host,r)?null:r?je(r,s,e.allowedOrigins)?{authenticatedByHeader:o}:null:o?{authenticatedByHeader:!0}:null}function Ue(t,e,n){let i=setTimeout(()=>{t.close(1008,"bridge authentication timeout")},De),o,s=()=>{clearTimeout(i),t.off("message",o),t.off("close",s)},r=()=>{s(),t.close(1008,"bridge authentication failed")};o=c=>{try{let p=m.parseMessage(c.toString());if(p.type!=="auth"||!ae(p.payload.key,e)){r();return}s(),t.readyState===ie.OPEN&&t.send(m.stringifyMessage({type:"auth-ok",payload:{ok:!0}})),n()}catch{r()}},t.on("message",o),t.on("close",s)}function ae(t,e){if(!t)return!1;let n=Buffer.from(t),i=Buffer.from(e);return n.length===i.length&&we(n,i)}function We(t,e,n){let i=ee(t),o=ee(e);return i===o||X(o)&&X(i)&&(!n||$(n,t))||$e(o)&&(!n||$(n,t))}function $e(t){return t==="0.0.0.0"||t==="::"}function X(t){return t==="localhost"||t==="127.0.0.1"||t==="::1"}function je(t,e,n){return n.includes(t)||(e?$(t,e):!1)}function $(t,e){try{return new URL(t).host===ce(e)}catch{return!1}}function ee(t){let e=ce(t);return e.startsWith("[")?e.slice(1,e.indexOf("]")):e.split(":").length-1===1?e.split(":",1)[0]??"":e}function ce(t){return t.trim().toLowerCase()}function q(t){return Array.isArray(t)?t[0]:t}function ze(){return Se(32).toString("base64url")}function Le(t){let e=t.replaceAll("\\","/");return e===V||e.endsWith(`/${V}`)}export{Me as SITE_EDIT_BRIDGE_MAX_BUFFERED_BYTES,se as SITE_EDIT_BRIDGE_MAX_PAYLOAD_BYTES,k as SiteEditBridgeServer,dt as attachSiteEditBridgeServer,Pe as attachSiteEditWebSocketServer,ht as createSiteEditBridgeEngineHost,ut as ensureSiteEditBridgeServerStarted,pt as normalizeSiteEditBridgeServerOptions};
4
+ `),r.destroy();return}p.authenticatedByHeader&&n.add(s),e.handleUpgrade(s,r,a,u=>{e.emit("connection",u,s)})};return t.server.on("upgrade",o),e.on("connection",(s,r)=>{if(n.has(r)){i(s);return}qe(s,t.sessionKey,()=>{i(s)})}),e.stop=()=>{t.server.off("upgrade",o);for(let s of e.clients)s.close(1001,"bridge stopped");e.close()},e}var W=class{constructor(e){this.socket=e,this.onmessage=null,this.onclose=null,e.on("error",()=>{}),e.on("message",n=>{this.onmessage?.({data:n.toString()})}),e.on("close",()=>{this.onclose?.()})}send(e){if(this.socket.readyState===ie.OPEN){if(this.socket.bufferedAmount+Buffer.byteLength(e,"utf8")>Me){this.socket.close(1013,"bridge backpressure");return}this.socket.send(e)}}close(e,n){this.socket.close(e,n)}};function Ve(t,e){return new URL(t.url??"/","http://localhost").pathname===e.path}function Ue(t,e){if(new URL(t.url??"/","http://localhost").searchParams.has("vcp_bridge_key"))return null;let i=V(t.headers["x-vcp-site-edit-key"]),o=ae(i,e.sessionKey),s=V(t.headers.host),r=V(t.headers.origin);return s&&!We(s,e.host,r)?null:r?je(r,s,e.allowedOrigins)?{authenticatedByHeader:o}:null:o?{authenticatedByHeader:!0}:null}function qe(t,e,n){let i=setTimeout(()=>{t.close(1008,"bridge authentication timeout")},De),o,s=()=>{clearTimeout(i),t.off("message",o),t.off("close",s)},r=()=>{s(),t.close(1008,"bridge authentication failed")};o=a=>{try{let p=g.parseMessage(a.toString());if(p.type!=="auth"||!ae(p.payload.key,e)){r();return}s(),t.readyState===ie.OPEN&&t.send(g.stringifyMessage({type:"auth-ok",payload:{ok:!0}})),n()}catch{r()}},t.on("message",o),t.on("close",s)}function ae(t,e){if(!t)return!1;let n=Buffer.from(t),i=Buffer.from(e);return n.length===i.length&&we(n,i)}function We(t,e,n){let i=te(t),o=te(e);return i===o||ee(o)&&ee(i)&&(!n||$(n,t))||$e(o)&&(!n||$(n,t))}function $e(t){return t==="0.0.0.0"||t==="::"}function ee(t){return t==="localhost"||t==="127.0.0.1"||t==="::1"}function je(t,e,n){return n.includes(t)||(e?$(t,e):!1)}function $(t,e){try{return new URL(t).host===ce(e)}catch{return!1}}function te(t){let e=ce(t);return e.startsWith("[")?e.slice(1,e.indexOf("]")):e.split(":").length-1===1?e.split(":",1)[0]??"":e}function ce(t){return t.trim().toLowerCase()}function V(t){return Array.isArray(t)?t[0]:t}function ze(){return Se(32).toString("base64url")}function Le(t){let e=t.replaceAll("\\","/");return e===U||e.endsWith(`/${U}`)}export{Me as SITE_EDIT_BRIDGE_MAX_BUFFERED_BYTES,se as SITE_EDIT_BRIDGE_MAX_PAYLOAD_BYTES,k as SiteEditBridgeServer,dt as attachSiteEditBridgeServer,Pe as attachSiteEditWebSocketServer,ht as createSiteEditBridgeEngineHost,ut as ensureSiteEditBridgeServerStarted,pt as normalizeSiteEditBridgeServerOptions};
@@ -328,7 +328,7 @@ export type SiteEditFrameRuntimeRequestBody = {
328
328
  } | {
329
329
  type: "request";
330
330
  id: string;
331
- kind: "bridge-execute";
331
+ kind: "bridge-execute" | "bridge-get-operation-result";
332
332
  payload: {
333
333
  composition: SiteEditCompositionSelector;
334
334
  request: SiteEditOperationRequest;
@@ -487,7 +487,7 @@ export type SiteEditFrameRuntimeResponseBody = {
487
487
  result?: SiteEditFrameRuntimeStarted | SiteEditFrameRuntimeHit | SiteEditFrameRuntimeNodePatchAck | SiteEditFrameRuntimeHit[] | SiteEditFrameRuntimeDropTarget | SiteEditFrameRuntimeScrollMetrics | SiteEditCommandSuccess<SiteEditRenderDocument> | SiteEditCommandSuccess<{
488
488
  document: SiteEditRenderDocument;
489
489
  historyStatus: SiteEditHistoryStatus;
490
- }> | SiteEditCommandSuccess<SiteEditHistoryStatus> | SiteEditCommandSuccess<SiteEditClassNameSourceStyleContext | null> | SiteEditCommandSuccess<SiteEditObjectEditContext> | SiteEditGetClassNameSourceCommandResult | SiteEditCommandSuccess<SiteEditSourceTreeResponse> | SiteEditCommandSuccess<SiteEditSourceFileResponse> | SiteEditCommandSuccess<SiteEditSourceLocation> | SiteEditOperationCommandResult | (SiteEditFrameRuntimeScrollMetrics & {
490
+ }> | SiteEditCommandSuccess<SiteEditHistoryStatus> | SiteEditCommandSuccess<SiteEditClassNameSourceStyleContext | null> | SiteEditCommandSuccess<SiteEditObjectEditContext> | SiteEditGetClassNameSourceCommandResult | SiteEditCommandSuccess<SiteEditSourceTreeResponse> | SiteEditCommandSuccess<SiteEditSourceFileResponse> | SiteEditCommandSuccess<SiteEditSourceLocation> | SiteEditOperationCommandResult | null | (SiteEditFrameRuntimeScrollMetrics & {
491
491
  scrolled: true;
492
492
  }) | {
493
493
  interactionEnabled: boolean;