@vcp-dev/site-edit-bridge 0.10.22 → 0.10.24

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,6 +1,6 @@
1
- import Ee from"node:http";import{existsSync as U,readFileSync as j}from"node:fs";import{randomUUID as Qt}from"node:crypto";import{createRequire as Ve}from"node:module";import{Socket as Ke}from"node:net";import q from"node:path";import{basename as Le,dirname as z,join as G}from"node:path";import{fileURLToPath as qe}from"node:url";import{Worker as Kt}from"node:worker_threads";var Ce=["resolveComposition","initializeSession","getDocument","getHistoryStatus","getStyleContext","getObjectEditContext","getClassNameSource","getSourceTree","getSourceFile","resolveSourceLocation","execute","undo","redo"];function te(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 L from"node:fs";import{createHash as Ae,randomBytes as ht,timingSafeEqual as pt}from"node:crypto";import v from"node:path";import{WebSocket as Oe,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 Re(e){let t=new Map,n=[],i=new Map,s=[],o=e.pageComposition.status==="supported"?e.pageComposition.placementUnitKeys:[],r=new Map(o.map((a,f)=>[a,f])),u=e.pageComposition.status==="supported"?{status:"supported",containerKey:e.pageComposition.containerKey,hasBusinessMembers:e.pageComposition.hasBusinessMembers,placementUnitKeys:e.pageComposition.placementUnitKeys,placements:e.pageComposition.placements.map(a=>({placementKey:a.placementKey,placementUnitKey:a.placementUnitKey,relation:a.relation}))}:{status:"unsupported",reason:e.pageComposition.reason,diagnostics:e.pageComposition.diagnostics},p=e.entries.flatMap((a,f)=>a.dynamicDataSummary?[[f,a.dynamicDataSummary]]:[]),c=a=>{let f=t.get(a);if(typeof f=="number")return f;let m=n.length;return n.push(a),t.set(a,m),m},l=a=>{let f=null;for(let m of tt(a)){let y=`${f??"root"}\0${m}`,S=i.get(y);if(typeof S=="number"){f=S;continue}let E=s.length;s.push([f,c(m)]),i.set(y,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:u,tokens:n,nodes:s,entries:e.entries.map(a=>{let f=a.pageCompositionUnitKey?r.get(a.pageCompositionUnitKey)??-1:-1;if(a.pageCompositionUnitKey&&f<0)throw new Error(`Render entry ${a.key} references unknown page composition unit ${a.pageCompositionUnitKey}`);return[l(a.key),et(a.operationSummary),...f>=0?[f]:[]]}),...e.entries.every(a=>a.parentKey!==void 0)?{entryParentNodeIds:e.entries.map(a=>a.parentKey===null?null:l(a.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 be="SITE_EDIT_COMPOSITION_SESSION_MISMATCH",ce="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(g(t)&&g(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!g(t)||typeof t.type!="string"?!1:t.type==="request"?nt(t.payload,n):t.type==="response"||t.type==="error"?g(t.payload)&&typeof t.payload.id=="string":t.type==="event"?g(t.payload)&&g(t.payload.event):t.type==="auth"?g(t.payload)&&typeof t.payload.key=="string":t.type==="auth-ok"&&g(t.payload)&&t.payload.ok===!0}},J=class{constructor(t){this.options=t,this.session={subscribedCompositionKeys:new Set},this.messageQueue=new ae,this.eventDispatcher=new re(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=ne(i),r=await this.resolve(o),u=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:k({...u,data:{...u.data,document:Te(u.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,k(r,o));return}case"get-style-context":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,k(await this.options.engine.getStyleContext(o),o));return}case"get-object-edit-context":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,k(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,k(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,k(await this.options.engine.getSourceTree(o),o));return}case"get-source-file":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,k(await this.options.engine.getSourceFile({path:i.path,composition:o}),o));return}case"resolve-source-location":{let o=await this.resolveWireContext(i),r=k(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 A(be,"The execute request composition does not match its operation composition.");let u=await this.normalizeOperationRequest(i.request,o);await this.handleBufferedOperation(s,i.kind,()=>this.options.engine.execute(u));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:oe(n),code:se(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 A(ce,"Initialize a composition session before issuing this request.");if(N(i)!==N(n.context))throw new A(be,"The request composition does not match the active socket session.");return n.context}async resolveWireContext(t){let n=ne(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:_e(n)};if(i.target.kind==="route"){let s=i.target,o=ne(s),r=await this.resolveAndAssert(o);i.target={...s,composition:_e(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(C.parseMessage(t,{validateOperationRequest:this.options.validateOperationRequest}))}catch(n){let i=ut(t);this.sendJson({type:"error",payload:{...i,message:oe(n),code:se(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:oe(s),code:se(s)}})}finally{this.eventDispatcher.flush()}}},A=class extends Error{constructor(t,n){super(n),this.code=t,this.name="BridgeProtocolError"}},re=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))}},ae=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(!g(e)||typeof e.id!="string"||!C.isRequestKind(e.kind))return!1;let n=V(e.composition);switch(e.kind){case"initialize-session":return n&&(e.mutationContext===void 0||ie(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||ie(e.request.mutationContext))&&(t.validateOperationRequest?.(e.request)??!0);case"undo":case"redo":return n&&e.mutationContext===void 0||n&&ie(e.mutationContext)}}function it(e){if(e===void 0)return!0;if(!g(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 g(e)&&typeof e.id=="string"&&typeof e.siteId=="string"&&typeof e.baseSnapshotId=="string"&&V(e.composition)&&typeof e.kind=="string"&&g(e.target)&&(e.target.kind!=="route"||V(e.target.composition))&&typeof e.documentVersion=="number"&&Number.isInteger(e.documentVersion)&&e.documentVersion>=0&&g(e.params)}function V(e){return g(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 g(e)&&typeof e.routeId=="string"&&(e.effectiveTemplateId===void 0||typeof e.effectiveTemplateId=="string")}function ne(e){if(V(e.composition))return e.composition;throw new A(ce,"A composition selector is required for this request.")}function rt(e){if(g(e)&&V(e.composition))return e.composition;throw new A(ce,"A composition selector is required for execute.")}function _e(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 k(e,t){return g(e)&&e.ok===!0?{...e,composition:t}:e}function ct(e,t){return!g(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 g(e){return typeof e=="object"&&e!==null}function ie(e){return g(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 se(e){if(!(!g(e)||typeof e.code!="string"||e.code.length===0))return e.code}function oe(e){return e instanceof Error||g(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 Q=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 O}from"@vcp-dev/contracts";var xt="127.0.0.1",Ct=30218,vt="/__vcp/site-edit/bridge",De=6*1024*1024,Rt=De*2,bt=3e3,ke=50,he=".vcp/current-snapshot.json",Pe="__VCP_SITE_EDIT_BRIDGE_SERVERS__";function Me(e,t,n={}){let i=new pe(je(t),e,!1,n);return i.start({listen:!1}),i}var pe=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 Q,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{L.mkdirSync(v.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=me({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??ke,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=Ht(),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=kt(t.composition),s=this.getRuntime(),o=R(i);await s.initializeComposition(o);let u=s.getDocument(o).data;await this.recordRuntimeVersion(u.version,i);let p=(await s.getHistoryStatus()).data;return{ok:!0,composition:i,data:{document:u,historyStatus:p}}}),getDocument:async t=>{let n=this.getRuntime(),i=R(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(R(t)),getObjectEditContext:async(t,n,i)=>this.getRuntime().getObjectEditContext(t,R(n),i),getClassNameSource:async(t,n)=>this.getRuntime().getClassNameSource(t,R(n)),getSourceTree:async t=>this.getRuntime().getSourceTree(R(t)),getSourceFile:async t=>this.getRuntime().getSourceFile({path:t.path,composition:R(t.composition)}),resolveSourceLocation:async t=>this.getRuntime().resolveSourceLocation({key:t.key,composition:R(t.composition)}),execute:(t,n)=>this.mutationQueue.run(async()=>{let i=await this.bindHistorySession(this.options.snapshotId);if(!i.ok)return ue(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 ue(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 ue(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=O(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?O(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??ke;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=L.readFileSync(v.join(this.options.projectRoot,he),"utf8"),n=JSON.parse(t),i=typeof n.snapshot_id=="string"?n.snapshot_id:"";return!i||le(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(u){console.warn(`[vcp-site-edit] snapshot.changed listener failed: ${u instanceof Error?u.message:String(u)}`)}}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=Tt(this.options.projectRoot),i=It(n),s=i.length>0?i:(this.options.runtime.routes??[]).map(c=>({...c})),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(c=>c.context.effectiveTemplateId!==void 0).map(c=>c.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 u=new Map(this.compositions.map(c=>[O(c.context),c])),p=new Map(o.map(c=>[O(c.context),c]));if(this.runtime){for(let[c,l]of u){let a=p.get(c);(!a||a.entryFile!==l.entryFile)&&this.runtime.unregisterComposition(R(l.context))}for(let[c,l]of p){let a=u.get(c);(!a||a.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=O(s.context);if(!this.compositions.some(r=>O(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(O(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 Be(e){return je(e)}function je(e){return{tenantId:e.tenantId,siteId:e.siteId,snapshotId:e.snapshotId,projectRoot:v.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 Tt(e){let t=[],n=["app","src/app",".vcp"],i=new Set([".git",".next",".turbo","coverage","dist","node_modules","output","snapshot-store"]),s=o=>{if(!L.existsSync(o))return;let r;try{r=L.readdirSync(o,{withFileTypes:!0})}catch{return}for(let u of r){if(u.name.startsWith(".")&&u.name!==".vcp")continue;if(u.isDirectory()){if(i.has(u.name))continue;s(v.join(o,u.name));continue}if(!u.isFile())continue;let p=v.join(o,u.name),c="";try{c=L.readFileSync(p,"utf8")}catch{}t.push({path:v.relative(e,p).replaceAll(v.sep,"/"),content:c})}};for(let o of n)s(v.join(e,o));return t.sort((o,r)=>o.path.localeCompare(r.path))}function kt(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 R(e){return{routeId:e.routeId,...e.effectiveTemplateId?{templateId:e.effectiveTemplateId}:{}}}function Pt(e){return v.join(v.resolve(e.root),le(e.siteId),le(e.snapshotId),Ae("sha256").update(e.editingSessionId).digest("hex").slice(0,32))}function le(e){return/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(e)&&e!=="."&&e!==".."?e:Ae("sha256").update(e).digest("hex").slice(0,32)}function Ht(){let e=globalThis;return e[Pe]??=new Map,e[Pe]}function Nt(e){return`${e.projectRoot}:${e.host}:${e.port}:${e.path}:${e.historyRoot??""}`}function ue(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 me(e){let t=new lt({maxPayload:De,noServer:!0}),n=new WeakSet,i=o=>{new J({socket:new fe(o),engine:e.engine,validateOperationRequest:r=>Et.safeParse(r).success})},s=(o,r,u)=>{if(!At(o,e))return;let p=Ot(o,e);if(!p){r.write(`HTTP/1.1 401 Unauthorized\r
1
+ import we from"node:http";import{existsSync as U,readFileSync as j}from"node:fs";import{randomUUID as Qt}from"node:crypto";import{createRequire as $e}from"node:module";import{Socket as Ke}from"node:net";import q from"node:path";import{basename as Le,dirname as z,join as G}from"node:path";import{fileURLToPath as qe}from"node:url";import{Worker as Kt}from"node:worker_threads";var Ce=["resolveComposition","initializeSession","getDocument","getHistoryStatus","getStyleContext","getObjectEditContext","getClassNameSource","getSourceTree","getSourceFile","resolveSourceLocation","execute","undo","redo"];function te(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 L from"node:fs";import{createHash as Ne,randomBytes as ht,timingSafeEqual as pt}from"node:crypto";import R 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 be(e){let t=new Map,n=[],i=new Map,s=[],o=e.pageComposition.status==="supported"?e.pageComposition.placementUnitKeys:[],r=new Map(o.map((d,g)=>[d,g])),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},l=e.entries.flatMap((d,g)=>d.dynamicDataSummary?[[g,d.dynamicDataSummary]]:[]),a=new Map(e.entries.map((d,g)=>[d.key,g])),f=[];for(let[d,g]of e.entries.entries()){let m=g.pageCompositionActionScope;if(!m)continue;if(m.kind!=="source-siblings"){f.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 "+g.key+" references missing source sibling "+E);return w});f.push([d,{kind:"source-siblings",siblingEntryIndexes:x}])}let u=d=>{let g=t.get(d);if(typeof g=="number")return g;let m=n.length;return n.push(d),t.set(d,m),m},S=d=>{let g=null;for(let m of tt(d)){let x=`${g??"root"}\0${m}`,E=i.get(x);if(typeof E=="number"){g=E;continue}let w=s.length;s.push([g,u(m)]),i.set(x,w),g=w}if(g===null)throw new Error("Document key must not be empty");return g};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 g=d.pageCompositionUnitKey?r.get(d.pageCompositionUnitKey)??-1:-1;if(d.pageCompositionUnitKey&&g<0)throw new Error(`Render entry ${d.key} references unknown page composition unit ${d.pageCompositionUnitKey}`);return[S(d.key),et(d.operationSummary),...g>=0?[g]:[]]}),...f.length>0?{pageCompositionActionScopes:f}:{},...e.entries.every(d=>d.parentKey!==void 0)?{entryParentNodeIds:e.entries.map(d=>d.parentKey===null?null:S(d.parentKey))}:{},...l.length>0?{dynamicDataSummaries:l}:{}}}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 Re="SITE_EDIT_COMPOSITION_SESSION_MISMATCH",ce="SITE_EDIT_COMPOSITION_SESSION_REQUIRED";var b=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}},J=class{constructor(t){this.options=t,this.session={subscribedCompositionKeys:new Set},this.messageQueue=new ae,this.eventDispatcher=new re(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=ne(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:A({...c,data:{...c.data,document:ke(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,A(r,o));return}case"get-style-context":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,A(await this.options.engine.getStyleContext(o),o));return}case"get-object-edit-context":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,A(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,A(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,A(await this.options.engine.getSourceTree(o),o));return}case"get-source-file":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,A(await this.options.engine.getSourceFile({path:i.path,composition:o}),o));return}case"resolve-source-location":{let o=await this.resolveWireContext(i),r=A(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(H(o)!==H(r))throw new N(Re,"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=b.extractRequestInfo(t);this.sendJson({type:"error",payload:{...i,message:oe(n),code:se(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 N(ce,"Initialize a composition session before issuing this request.");if(H(i)!==H(n.context))throw new N(Re,"The request composition does not match the active socket session.");return n.context}async resolveWireContext(t){let n=ne(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:_e(n)};if(i.target.kind==="route"){let s=i.target,o=ne(s),r=await this.resolveAndAssert(o);i.target={...s,composition:_e(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(b.parseMessage(t,{validateOperationRequest:this.options.validateOperationRequest}))}catch(n){let i=ut(t);this.sendJson({type:"error",payload:{...i,message:oe(n),code:se(n)}})}}sendJson(t){this.options.socket.send(b.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:oe(s),code:se(s)}})}finally{this.eventDispatcher.flush()}}},N=class extends Error{constructor(t,n){super(n),this.code=t,this.name="BridgeProtocolError"}},re=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))}},ae=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"||!b.isRequestKind(e.kind))return!1;let n=$(e.composition);switch(e.kind){case"initialize-session":return n&&(e.mutationContext===void 0||ie(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||ie(e.request.mutationContext))&&(t.validateOperationRequest?.(e.request)??!0);case"undo":case"redo":return n&&e.mutationContext===void 0||n&&ie(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"&&$(e.composition)&&typeof e.kind=="string"&&y(e.target)&&(e.target.kind!=="route"||$(e.target.composition))&&typeof e.documentVersion=="number"&&Number.isInteger(e.documentVersion)&&e.documentVersion>=0&&y(e.params)}function $(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 ne(e){if($(e.composition))return e.composition;throw new N(ce,"A composition selector is required for this request.")}function rt(e){if(y(e)&&$(e.composition))return e.composition;throw new N(ce,"A composition selector is required for execute.")}function _e(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 A(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:ke(e.data)}}function ke(e){let t=e;return be(t.routeId?t:{...t,routeId:t.composition.routeId})}function y(e){return typeof e=="object"&&e!==null}function ie(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 se(e){if(!(!y(e)||typeof e.code!="string"||e.code.length===0))return e.code}function oe(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 b.extractRequestInfo(JSON.parse(e))}catch{return{id:"unknown",kind:"get-document"}}}var Q=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",Oe=6*1024*1024,bt=Oe*2,Rt=3e3,Te=50,he=".vcp/current-snapshot.json",Pe="__VCP_SITE_EDIT_BRIDGE_SERVERS__";function De(e,t,n={}){let i=new pe(je(t),e,!1,n);return i.start({listen:!1}),i}var pe=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 Q,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{L.mkdirSync(R.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=me({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??Te,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 l=(await s.getHistoryStatus()).data;return{ok:!0,composition:i,data:{document:c,historyStatus:l}}}),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 ue(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 ue(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 ue(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??Te;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=L.readFileSync(R.join(this.options.projectRoot,he),"utf8"),n=JSON.parse(t),i=typeof n.snapshot_id=="string"?n.snapshot_id:"";return!i||le(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])),l=new Map(o.map(a=>[M(a.context),a]));if(this.runtime){for(let[a,f]of c){let u=l.get(a);(!u||u.entryFile!==f.entryFile)&&this.runtime.unregisterComposition(_(f.context))}for(let[a,f]of l){let u=c.get(a);(!u||u.entryFile!==f.entryFile)&&this.runtime.registerComposition(f.context,f.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 Be(e){return je(e)}function je(e){return{tenantId:e.tenantId,siteId:e.siteId,snapshotId:e.snapshotId,projectRoot:R.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(!L.existsSync(o))return;let r;try{r=L.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(R.join(o,c.name));continue}if(!c.isFile())continue;let l=R.join(o,c.name),a="";try{a=L.readFileSync(l,"utf8")}catch{}t.push({path:R.relative(e,l).replaceAll(R.sep,"/"),content:a})}};for(let o of n)s(R.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 R.join(R.resolve(e.root),le(e.siteId),le(e.snapshotId),Ne("sha256").update(e.editingSessionId).digest("hex").slice(0,32))}function le(e){return/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(e)&&e!=="."&&e!==".."?e:Ne("sha256").update(e).digest("hex").slice(0,32)}function At(){let e=globalThis;return e[Pe]??=new Map,e[Pe]}function Ht(e){return`${e.projectRoot}:${e.host}:${e.port}:${e.path}:${e.historyRoot??""}`}function ue(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 me(e){let t=new lt({maxPayload:Oe,noServer:!0}),n=new WeakSet,i=o=>{new J({socket:new fe(o),engine:e.engine,validateOperationRequest:r=>wt.safeParse(r).success})},s=(o,r,c)=>{if(!Nt(o,e))return;let l=Mt(o,e);if(!l){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,u,c=>{t.emit("connection",c,o)})};return e.server.on("upgrade",s),t.on("connection",(o,r)=>{if(n.has(r)){i(o);return}Dt(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 fe=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===Oe.OPEN){if(this.socket.bufferedAmount+Buffer.byteLength(t,"utf8")>Rt){this.socket.close(1013,"bridge backpressure");return}this.socket.send(t)}}close(t,n){this.socket.close(t,n)}};function At(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=de(e.headers["x-vcp-site-edit-key"]),s=Ue(i,t.sessionKey),o=de(e.headers.host),r=de(e.headers.origin);return o&&!Mt(o,t.host,r)?null:r?jt(r,o,t.allowedOrigins)?{authenticatedByHeader:s}:null:s?{authenticatedByHeader:!0}:null}function Dt(e,t,n){let i=setTimeout(()=>{e.close(1008,"bridge authentication timeout")},bt),s,o=()=>{clearTimeout(i),e.off("message",s),e.off("close",o)},r=()=>{o(),e.close(1008,"bridge authentication failed")};s=u=>{try{let p=C.parseMessage(u.toString());if(p.type!=="auth"||!Ue(p.payload.key,t)){r();return}o(),e.readyState===Oe.OPEN&&e.send(C.stringifyMessage({type:"auth-ok",payload:{ok:!0}})),n()}catch{r()}},e.on("message",s),e.on("close",o)}function Ue(e,t){if(!e)return!1;let n=Buffer.from(e),i=Buffer.from(t);return n.length===i.length&&pt(n,i)}function Mt(e,t,n){let i=Ne(e),s=Ne(t);return i===s||He(s)&&He(i)&&(!n||ge(n,e))||Bt(s)&&(!n||ge(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?ge(e,t):!1)}function ge(e,t){try{return new URL(e).host===Fe(t)}catch{return!1}}function Ne(e){let t=Fe(e);return t.startsWith("[")?t.slice(1,t.indexOf("]")):t.split(":").length-1===1?t.split(":",1)[0]??"":t}function Fe(e){return e.trim().toLowerCase()}function de(e){return Array.isArray(e)?e[0]:e}function Ut(){return ht(32).toString("base64url")}function Ft(e){let t=e.replaceAll("\\","/");return t===he||t.endsWith(`/${he}`)}var Wt="SITE_EDIT_ENGINE_UNAVAILABLE",$t=5e3,Vt=1024,Lt="VCP_SITE_EDIT_ENGINE_MAX_HEAP_MB",qt=3,zt=10*6e4,Gt=1012;function ye(e,t,n={}){let i=Be(t),{onSnapshotIdChanged:s,onHealthChanged:o,...r}=i,u={options:r},p=n.maxHeapMb??Jt(process.env[Lt])??Vt,c=n.maxRestarts??qt,l=n.restartWindowMs??zt,a="starting",f,m=0,y=[],S=null,E=0,P=new Map,H=new Set,F,D,K=new Promise((d,h)=>{F=d,D=h});K.catch(()=>{});let x=d=>{let h=new Error(`VCP site edit preview bridge runtime is not ready: ${d}`);return h.code=Wt,h},W=d=>{for(let h of P.values())h.reject(d);P.clear()},b=d=>{switch(d.type){case"ready":S=d.health,a==="starting"?(a="ready",F()):a==="restarting"&&(a="ready",console.warn("[vcp-site-edit] engine worker restarted"));return;case"start-failed":a==="starting"&&_(te(d.error));return;case"result":{let h=P.get(d.id);if(!h)return;P.delete(d.id),d.ok?h.resolve(d.value):h.reject(te(d.error));return}case"event":for(let h of H)try{h(d.event)}catch(I){console.warn(`[vcp-site-edit] engine event listener failed: ${I instanceof Error?I.message:String(I)}`)}return;case"health":S=d.health;return;case"snapshot-id-changed":u.options.snapshotId=d.next;try{s?.(d.next,d.previous)}catch(h){console.warn(`[vcp-site-edit] onSnapshotIdChanged callback failed: ${h instanceof Error?h.message:String(h)}`)}return}},M=()=>{let d=m+=1,h=new Kt(n.workerUrl??new URL("./engine-worker.js",import.meta.url),{workerData:u,resourceLimits:{maxOldGenerationSizeMb:p},...n.execArgv?{execArgv:n.execArgv}:{}});h.unref();let I=()=>d===m;h.on("message",w=>{I()&&b(w)}),h.on("error",w=>{I()&&_(w instanceof Error?w:new Error(String(w)))}),h.on("exit",w=>{I()&&_(new Error(`engine worker exited with code ${w}`))}),f=h,n.onWorker?.(h)},_=d=>{if(a==="stopped"||a==="failed")return;if(W(x(d.message)),S=null,a==="starting"){a="failed",console.error(`[vcp-site-edit] engine worker failed to start: ${d.message}`),D(d);return}let h=Date.now();for(;y.length>0&&h-y[0]>l;)y.shift();if(y.length>=c){a="failed",console.error(`[vcp-site-edit] engine worker stopped unexpectedly and exhausted ${c} restarts: ${d.message}`);return}y.push(h),a="restarting";for(let I of T.clients)I.close(Gt,"site edit engine restarting");console.error(`[vcp-site-edit] engine worker stopped unexpectedly, restarting (${y.length}/${c}): ${d.message}`),M()},$=(d,h)=>{if(a==="failed"||a==="stopped"||a==="restarting")return Promise.reject(x(a));let I=E+=1;return new Promise((w,Xe)=>{P.set(I,{resolve:w,reject:Xe});let Ze={type:"call",id:I,method:d,args:h};f.postMessage(Ze)})},B=Object.fromEntries(Ce.map(d=>[d,(...h)=>$(d,h)])),T=me({server:e,path:i.path,sessionKey:i.sessionKey,host:i.host,allowedOrigins:i.allowedOrigins,engine:{...B,subscribe(d){return H.add(d),()=>H.delete(d)}}});return M(),{getHealth(){return a==="ready"&&S?S:{ok:!1,bridgePath:i.path,runtimeReady:!1,routesIndexed:S?.routesIndexed??0,sessionRequired:!!i.sessionKey}},stop(){if(a==="stopped")return;let d=a==="starting";a="stopped",T.stop(),d&&D(x("bridge stopped")),W(x("bridge stopped")),H.clear();let h=f,I={type:"stop"};h.postMessage(I);let w=setTimeout(()=>{h.terminate()},$t);w.unref(),h.once("exit",()=>clearTimeout(w))},whenReady(){return K},eventListeners:H}}function Jt(e){if(!e||!/^\d+$/.test(e.trim()))return;let t=Number(e.trim());return Number.isSafeInteger(t)&&t>0?t:void 0}var Yt="next",Xt="VCP_SITE_EDIT_ENGINE_IN_PROCESS",ze="127.0.0.1",Zt=3e3,Z="/__vcp/site-edit/bridge",Ge="/__vcp/site-edit/health",en="probe",tn="render",We="/_error",ee="/__vcp/site-edit/client/",nn=`${ee}auto-bootstrap.js`,Je='data-vcp-site-edit-bootstrap="true"',sn=["next.config.ts","next.config.mts","next.config.cts","next.config.js","next.config.mjs","next.config.cjs"],on="@vcp-dev/site-edit-engine/webpack-loader",rn=/@vcp\/site-edit-engine\/(?:webpack-loader|site-edit-instrumentation-loader)/,an=[/\bconfig\.webpack\s*=/,/\bwebpack\s*\([^)]*\)\s*\{/,/\bwebpack\s*:\s*(?:async\s*)?(?:\([^)]*\)|[A-Za-z_$][\w$]*)?\s*=>/,/\bwebpack\s*:\s*(?:async\s+)?function\b/],cn=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 Ri(e={},t={}){let n=t.process??process,i=t.createServer??Ee.createServer,s=t.attachBridgeServer??(n.env[Xt]==="1"?Me:ye),o=t.loadNext??Un,r=q.resolve(e.projectRoot??process.cwd()),u=e.host??ze,p=e.port??$n(n.env.PORT)??Zt,c=e.bridgePath??Z,l=gn(c),a=On(),f=e.basePath??n.env.VCP_SITE_PREVIEW_BASE_PATH??"/",m=(e.tenantId??n.env.VCP_TENANT_ID)?.trim()||void 0,y=await o(r),S=un(r),E=y({dev:!0,dir:r,hostname:u,port:p,...dn(S)}),P=E.getRequestHandler(),H=e.siteId??n.env.VCP_SITE_ID??"018f6f4d-a9b8-7120-8000-000000000120",F=e.snapshotId??n.env.VCP_SNAPSHOT_ID??Wn(r),D=e.historyRoot??n.env.VCP_SITE_EDIT_HISTORY_ROOT,K=D?.trim()?q.resolve(D):void 0,x=null,W={launchId:Qt(),pid:process.pid,snapshotId:F},b=i((T,d)=>{xn({basePath:f,bridgePath:c,bridgeHealthPath:l,bridgeSessionKey:a,getBridgeHealth:()=>x?.getHealth()??Tn(c),launch:W,runRenderProbe:()=>Rn(E),handle:P,request:T,response:d}).catch(h=>{console.error(h),d.headersSent||(d.statusCode=500),d.end("site edit preview request failed")})}),M=null,_=null,$=()=>_||(X(()=>n.off("SIGINT",B)),X(()=>n.off("SIGTERM",B)),X(()=>M?.()),M=null,X(()=>x?.stop()),x=null,_=Promise.allSettled([Ln(b),qn(()=>E.close())]).then(()=>{}),_),B=()=>{$()};try{return await E.prepare(),x=s(b,{...m?{tenantId:m}:{},siteId:H,snapshotId:F,projectRoot:r,basePath:f,host:u,port:p,path:c,sessionKey:a,...K?{historyRoot:K}:{},onSnapshotIdChanged:T=>{W.snapshotId=T}}),M=ln({server:b,bridgePath:c,handleUpgrade:E.getUpgradeHandler()}),n.on("SIGINT",B),n.on("SIGTERM",B),await x.whenReady?.(),await Vn(b,p,u),{bundler:S,close:$,host:u,port:zn(b,p),server:b}}catch(T){throw await $(),T}}function un(e){let t=hn(e);return t&&pn(t)?"webpack":"turbopack"}function dn(e){return e==="webpack"?{webpack:!0}:{turbopack:!0}}function hn(e){for(let t of sn){let n=G(e,t);if(U(n))return j(n,"utf8")}return null}function pn(e){return e.includes(on)?!0:rn.test(e)&&an.some(t=>t.test(e))}function ln(e){let t=(n,i,s)=>{fn(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 fn(e,t){return new URL(e??"/","http://localhost").pathname===t}function gn(e=Z){if(e===Z)return Ge;let t=(e.startsWith("/")?e:`/${e}`).replace(/\/+$/,"");return t.endsWith("/bridge")?`${t.slice(0,-7)}/health`:t?`${t}/health`:"/health"}function mn(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??yn()});return`<script type="module" ${Je}>import { startSiteEditAutoBootstrap } from ${JSON.stringify(nn)};void startSiteEditAutoBootstrap(window, ${t}).catch(() => undefined);</script>`}function yn(){return{bridge:Se("@vcp-dev/site-edit-bridge"),contracts:Se("@vcp-dev/contracts"),engine:Se("@vcp-dev/site-edit-engine")}}function Se(e){let t=Ve(import.meta.url);try{let n=t.resolve(e),i=Sn(n,e);if(!i)return;let s=JSON.parse(j(i,"utf8"));return typeof s.version=="string"?s.version:void 0}catch{return}}function Sn(e,t){let n=q.parse(e).root,i=z(e);for(;i&&i!==n;){let s=G(i,"package.json");if(U(s))try{if(JSON.parse(j(s,"utf8")).name===t)return s}catch{return}i=z(i)}}function In(e,t){if(e.includes(Je))return e;let n=mn(t),i=/<\/body\s*>/i.exec(e);return i?`${e.slice(0,i.index)}${n}${e.slice(i.index)}`:`${e}${n}`}function bi(e,t=z(qe(import.meta.url)),n=U){return Qe(e,t,n)?.path??null}function Qe(e,t=z(qe(import.meta.url)),n=U){let i=new URL(e??"/","http://localhost").pathname;if(!i.startsWith(ee))return null;let s=i.slice(ee.length);if(!cn.has(s))return null;let o=xe(Fn(t),s);if(Le(t)!=="src")return{path:o,requiresTranspile:!1};let r=xe(t,s.replace(/\.js$/,".ts"));return n(r)?{path:r,requiresTranspile:!0}:{path:o,requiresTranspile:!1}}async function wn(e,t){let n=Qe(e.url);if(!n)return!1;if(!U(n.path))return t.writeHead(404),t.end("site edit client asset not found"),!0;let i=n.requiresTranspile?await En(j(n.path,"utf8")):j(n.path);return t.writeHead(200,{"cache-control":"no-store","content-type":"text/javascript; charset=utf-8"}),t.end(i),!0}async function En(e){let t=await import("typescript");return t.transpileModule(e,{compilerOptions:{module:t.ModuleKind.ES2022,target:t.ScriptTarget.ES2022}}).outputText}async function xn({basePath:e,bridgePath:t,bridgeHealthPath:n,bridgeSessionKey:i,getBridgeHealth:s,launch:o,runRenderProbe:r,handle:u,request:p,response:c}){if(Cn(p.url,e)){c.statusCode=404,c.end();return}if(await _n(p,c,n,s,o,r)||await wn(p,c))return;let l=kn(p),a=Pn(p),f=l||a?An(c,{basePath:e,bridgePath:t,bridgeSessionKey:i,patchNextDevChunk:a,launch:{...o}}):()=>{};try{await u(p,c)}catch(m){throw f(),m}}function Cn(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 vn(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 Rn(e){let t=new Ee.IncomingMessage(new Ke);t.method="GET",t.url=We,t.headers={host:ze};let n=new Ee.ServerResponse(t);n.assignSocket(new Ke);try{return await e.renderToHTML(t,n,We,{}),{verdict:"ok"}}catch(i){return vn(i)}finally{try{let i=n.socket;i&&(n.detachSocket(i),i.destroy())}catch{}}}function bn(e){return new URL(e??"/","http://localhost").searchParams.get(en)===tn}async function _n(e,t,n,i,s,o){if(e.method!=="GET"||new URL(e.url??"/","http://localhost").pathname!==n)return!1;let u=i(),p=bn(e.url)?await o():void 0,c={...u,launch:s,...p?{render:p}:{}};return t.writeHead(u.ok?200:503,{"cache-control":"no-store","content-type":"application/json; charset=utf-8"}),t.end(JSON.stringify(c)),!0}function Tn(e){return{ok:!1,bridgePath:e,runtimeReady:!1,routesIndexed:0,sessionRequired:!0}}function kn(e){return Hn(e)?(e.headers["accept-encoding"]="identity",!0):!1}function Pn(e){return Nn(e)?(e.headers["accept-encoding"]="identity",!0):!1}function Hn(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(ee)||n===Z||n===Ge)return!1;let i=e.headers.accept??"";return i===""||i.includes("text/html")}function Nn(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 An(e,t){let n=[],i=e,s=i.flushHeaders.bind(e),o=i.write.bind(e),r=i.end.bind(e),u=!1;i.flushHeaders=()=>{};let p=()=>{if(t.patchNextDevChunk||u)return!1;let c=Buffer.concat(n);if(!/<body\b[^>]*>/iu.test(c.toString("utf8")))return!1;let l=$e(e,c,t);return l!==c&&!e.headersSent&&e.removeHeader("content-length"),o(l),n.length=0,u=!0,!0};return i.write=(c,l,a)=>u?(c!==void 0&&o(Ie(c,we(l))),Y(l),Y(a),!0):(c!==void 0&&(n.push(Ie(c,we(l))),p()),Y(l),Y(a),!0),i.end=(c,l,a)=>{let f=typeof c=="function"?void 0:c;if(u)return i.write=o,i.end=r,i.flushHeaders=s,f===void 0?typeof c=="function"?r(c):typeof l=="function"?r(l):typeof a=="function"?r(a):r():typeof l=="function"?r(f,l):typeof a=="function"?r(f,l,a):r(f,l);f!==void 0&&n.push(Ie(f,we(l))),i.write=o,i.end=r,i.flushHeaders=s;let m=Buffer.concat(n),y=$e(e,m,t);y!==m&&!e.headersSent&&e.removeHeader("content-length");let S=typeof c=="function"?c:typeof l=="function"?l:typeof a=="function"?a:void 0;return S?r(y,S):r(y)},()=>{i.write=o,i.end=r,i.flushHeaders=s}}function $e(e,t,n){if(Dn(e,t))return Buffer.from(In(t.toString("utf8"),n));if(n.patchNextDevChunk&&Mn(e)){let i=t.toString("utf8"),s=Bn(i);if(s!==i)return Buffer.from(s)}return t}function On(){let e=new Uint8Array(32);return globalThis.crypto.getRandomValues(e),Buffer.from(e).toString("base64url")}function Dn(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 Mn(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 Bn(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}l.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}Ot(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 fe=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 Mt(e,t){if(new URL(e.url??"/","http://localhost").searchParams.has("vcp_bridge_key"))return null;let i=de(e.headers["x-vcp-site-edit-key"]),s=Ue(i,t.sessionKey),o=de(e.headers.host),r=de(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 Ot(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 l=b.parseMessage(c.toString());if(l.type!=="auth"||!Ue(l.payload.key,t)){r();return}o(),e.readyState===Me.OPEN&&e.send(b.stringifyMessage({type:"auth-ok",payload:{ok:!0}})),n()}catch{r()}},e.on("message",s),e.on("close",o)}function Ue(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=He(e),s=He(t);return i===s||Ae(s)&&Ae(i)&&(!n||ge(n,e))||Bt(s)&&(!n||ge(n,e))}function Bt(e){return e==="0.0.0.0"||e==="::"}function Ae(e){return e==="localhost"||e==="127.0.0.1"||e==="::1"}function jt(e,t,n){return n.includes(e)||(t?ge(e,t):!1)}function ge(e,t){try{return new URL(e).host===Fe(t)}catch{return!1}}function He(e){let t=Fe(e);return t.startsWith("[")?t.slice(1,t.indexOf("]")):t.split(":").length-1===1?t.split(":",1)[0]??"":t}function Fe(e){return e.trim().toLowerCase()}function de(e){return Array.isArray(e)?e[0]:e}function Ut(){return ht(32).toString("base64url")}function Ft(e){let t=e.replaceAll("\\","/");return t===he||t.endsWith(`/${he}`)}var Wt="SITE_EDIT_ENGINE_UNAVAILABLE",Vt=5e3,$t=1024,Lt="VCP_SITE_EDIT_ENGINE_MAX_HEAP_MB",qt=3,zt=10*6e4,Gt=1012;function ye(e,t,n={}){let i=Be(t),{onSnapshotIdChanged:s,onHealthChanged:o,...r}=i,c={options:r},l=n.maxHeapMb??Jt(process.env[Lt])??$t,a=n.maxRestarts??qt,f=n.restartWindowMs??zt,u="starting",S,d=0,g=[],m=null,x=0,E=new Map,w=new Set,F,O,K=new Promise((h,p)=>{F=h,O=p});K.catch(()=>{});let v=h=>{let p=new Error(`VCP site edit preview bridge runtime is not ready: ${h}`);return p.code=Wt,p},W=h=>{for(let p of E.values())p.reject(h);E.clear()},k=h=>{switch(h.type){case"ready":m=h.health,u==="starting"?(u="ready",F()):u==="restarting"&&(u="ready",console.warn("[vcp-site-edit] engine worker restarted"));return;case"start-failed":u==="starting"&&T(te(h.error));return;case"result":{let p=E.get(h.id);if(!p)return;E.delete(h.id),h.ok?p.resolve(h.value):p.reject(te(h.error));return}case"event":for(let p of w)try{p(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(p){console.warn(`[vcp-site-edit] onSnapshotIdChanged callback failed: ${p instanceof Error?p.message:String(p)}`)}return}},D=()=>{let h=d+=1,p=new Kt(n.workerUrl??new URL("./engine-worker.js",import.meta.url),{workerData:c,resourceLimits:{maxOldGenerationSizeMb:l},...n.execArgv?{execArgv:n.execArgv}:{}});p.unref();let I=()=>h===d;p.on("message",C=>{I()&&k(C)}),p.on("error",C=>{I()&&T(C instanceof Error?C:new Error(String(C)))}),p.on("exit",C=>{I()&&T(new Error(`engine worker exited with code ${C}`))}),S=p,n.onWorker?.(p)},T=h=>{if(u==="stopped"||u==="failed")return;if(W(v(h.message)),m=null,u==="starting"){u="failed",console.error(`[vcp-site-edit] engine worker failed to start: ${h.message}`),O(h);return}let p=Date.now();for(;g.length>0&&p-g[0]>f;)g.shift();if(g.length>=a){u="failed",console.error(`[vcp-site-edit] engine worker stopped unexpectedly and exhausted ${a} restarts: ${h.message}`);return}g.push(p),u="restarting";for(let I of P.clients)I.close(Gt,"site edit engine restarting");console.error(`[vcp-site-edit] engine worker stopped unexpectedly, restarting (${g.length}/${a}): ${h.message}`),D()},V=(h,p)=>{if(u==="failed"||u==="stopped"||u==="restarting")return Promise.reject(v(u));let I=x+=1;return new Promise((C,Xe)=>{E.set(I,{resolve:C,reject:Xe});let Ze={type:"call",id:I,method:h,args:p};S.postMessage(Ze)})},B=Object.fromEntries(Ce.map(h=>[h,(...p)=>V(h,p)])),P=me({server:e,path:i.path,sessionKey:i.sessionKey,host:i.host,allowedOrigins:i.allowedOrigins,engine:{...B,subscribe(h){return w.add(h),()=>w.delete(h)}}});return D(),{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&&O(v("bridge stopped")),W(v("bridge stopped")),w.clear();let p=S,I={type:"stop"};p.postMessage(I);let C=setTimeout(()=>{p.terminate()},Vt);C.unref(),p.once("exit",()=>clearTimeout(C))},whenReady(){return K},eventListeners:w}}function Jt(e){if(!e||!/^\d+$/.test(e.trim()))return;let t=Number(e.trim());return Number.isSafeInteger(t)&&t>0?t:void 0}var Yt="next",Xt="VCP_SITE_EDIT_ENGINE_IN_PROCESS",ze="127.0.0.1",Zt=3e3,Z="/__vcp/site-edit/bridge",Ge="/__vcp/site-edit/health",en="probe",tn="render",We="/_error",ee="/__vcp/site-edit/client/",nn=`${ee}auto-bootstrap.js`,Je='data-vcp-site-edit-bootstrap="true"',sn=["next.config.ts","next.config.mts","next.config.cts","next.config.js","next.config.mjs","next.config.cjs"],on="@vcp-dev/site-edit-engine/webpack-loader",rn=/@vcp\/site-edit-engine\/(?:webpack-loader|site-edit-instrumentation-loader)/,an=[/\bconfig\.webpack\s*=/,/\bwebpack\s*\([^)]*\)\s*\{/,/\bwebpack\s*:\s*(?:async\s*)?(?:\([^)]*\)|[A-Za-z_$][\w$]*)?\s*=>/,/\bwebpack\s*:\s*(?:async\s+)?function\b/],cn=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 bi(e={},t={}){let n=t.process??process,i=t.createServer??we.createServer,s=t.attachBridgeServer??(n.env[Xt]==="1"?De:ye),o=t.loadNext??Un,r=q.resolve(e.projectRoot??process.cwd()),c=e.host??ze,l=e.port??Vn(n.env.PORT)??Zt,a=e.bridgePath??Z,f=gn(a),u=Mn(),S=e.basePath??n.env.VCP_SITE_PREVIEW_BASE_PATH??"/",d=(e.tenantId??n.env.VCP_TENANT_ID)?.trim()||void 0,g=await o(r),m=un(r),x=g({dev:!0,dir:r,hostname:c,port:l,...dn(m)}),E=x.getRequestHandler(),w=e.siteId??n.env.VCP_SITE_ID??"018f6f4d-a9b8-7120-8000-000000000120",F=e.snapshotId??n.env.VCP_SNAPSHOT_ID??Wn(r),O=e.historyRoot??n.env.VCP_SITE_EDIT_HISTORY_ROOT,K=O?.trim()?q.resolve(O):void 0,v=null,W={launchId:Qt(),pid:process.pid,snapshotId:F},k=i((P,h)=>{xn({basePath:S,bridgePath:a,bridgeHealthPath:f,bridgeSessionKey:u,getBridgeHealth:()=>v?.getHealth()??kn(a),launch:W,runRenderProbe:()=>bn(x),handle:E,request:P,response:h}).catch(p=>{console.error(p),h.headersSent||(h.statusCode=500),h.end("site edit preview request failed")})}),D=null,T=null,V=()=>T||(X(()=>n.off("SIGINT",B)),X(()=>n.off("SIGTERM",B)),X(()=>D?.()),D=null,X(()=>v?.stop()),v=null,T=Promise.allSettled([Ln(k),qn(()=>x.close())]).then(()=>{}),T),B=()=>{V()};try{return await x.prepare(),v=s(k,{...d?{tenantId:d}:{},siteId:w,snapshotId:F,projectRoot:r,basePath:S,host:c,port:l,path:a,sessionKey:u,...K?{historyRoot:K}:{},onSnapshotIdChanged:P=>{W.snapshotId=P}}),D=ln({server:k,bridgePath:a,handleUpgrade:x.getUpgradeHandler()}),n.on("SIGINT",B),n.on("SIGTERM",B),await v.whenReady?.(),await $n(k,l,c),{bundler:m,close:V,host:c,port:zn(k,l),server:k}}catch(P){throw await V(),P}}function un(e){let t=hn(e);return t&&pn(t)?"webpack":"turbopack"}function dn(e){return e==="webpack"?{webpack:!0}:{turbopack:!0}}function hn(e){for(let t of sn){let n=G(e,t);if(U(n))return j(n,"utf8")}return null}function pn(e){return e.includes(on)?!0:rn.test(e)&&an.some(t=>t.test(e))}function ln(e){let t=(n,i,s)=>{fn(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 fn(e,t){return new URL(e??"/","http://localhost").pathname===t}function gn(e=Z){if(e===Z)return Ge;let t=(e.startsWith("/")?e:`/${e}`).replace(/\/+$/,"");return t.endsWith("/bridge")?`${t.slice(0,-7)}/health`:t?`${t}/health`:"/health"}function mn(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??yn()});return`<script type="module" ${Je}>import { startSiteEditAutoBootstrap } from ${JSON.stringify(nn)};void startSiteEditAutoBootstrap(window, ${t}).catch(() => undefined);</script>`}function yn(){return{bridge:Se("@vcp-dev/site-edit-bridge"),contracts:Se("@vcp-dev/contracts"),engine:Se("@vcp-dev/site-edit-engine")}}function Se(e){let t=$e(import.meta.url);try{let n=t.resolve(e),i=Sn(n,e);if(!i)return;let s=JSON.parse(j(i,"utf8"));return typeof s.version=="string"?s.version:void 0}catch{return}}function Sn(e,t){let n=q.parse(e).root,i=z(e);for(;i&&i!==n;){let s=G(i,"package.json");if(U(s))try{if(JSON.parse(j(s,"utf8")).name===t)return s}catch{return}i=z(i)}}function In(e,t){if(e.includes(Je))return e;let n=mn(t),i=/<\/body\s*>/i.exec(e);return i?`${e.slice(0,i.index)}${n}${e.slice(i.index)}`:`${e}${n}`}function Ri(e,t=z(qe(import.meta.url)),n=U){return Qe(e,t,n)?.path??null}function Qe(e,t=z(qe(import.meta.url)),n=U){let i=new URL(e??"/","http://localhost").pathname;if(!i.startsWith(ee))return null;let s=i.slice(ee.length);if(!cn.has(s))return null;let o=xe(Fn(t),s);if(Le(t)!=="src")return{path:o,requiresTranspile:!1};let r=xe(t,s.replace(/\.js$/,".ts"));return n(r)?{path:r,requiresTranspile:!0}:{path:o,requiresTranspile:!1}}async function En(e,t){let n=Qe(e.url);if(!n)return!1;if(!U(n.path))return t.writeHead(404),t.end("site edit client asset not found"),!0;let i=n.requiresTranspile?await wn(j(n.path,"utf8")):j(n.path);return t.writeHead(200,{"cache-control":"no-store","content-type":"text/javascript; charset=utf-8"}),t.end(i),!0}async function wn(e){let t=await import("typescript");return t.transpileModule(e,{compilerOptions:{module:t.ModuleKind.ES2022,target:t.ScriptTarget.ES2022}}).outputText}async function xn({basePath:e,bridgePath:t,bridgeHealthPath:n,bridgeSessionKey:i,getBridgeHealth:s,launch:o,runRenderProbe:r,handle:c,request:l,response:a}){if(Cn(l.url,e)){a.statusCode=404,a.end();return}if(await _n(l,a,n,s,o,r)||await En(l,a))return;let f=Tn(l),u=Pn(l),S=f||u?Nn(a,{basePath:e,bridgePath:t,bridgeSessionKey:i,patchNextDevChunk:u,launch:{...o}}):()=>{};try{await c(l,a)}catch(d){throw S(),d}}function Cn(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 vn(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 bn(e){let t=new we.IncomingMessage(new Ke);t.method="GET",t.url=We,t.headers={host:ze};let n=new we.ServerResponse(t);n.assignSocket(new Ke);try{return await e.renderToHTML(t,n,We,{}),{verdict:"ok"}}catch(i){return vn(i)}finally{try{let i=n.socket;i&&(n.detachSocket(i),i.destroy())}catch{}}}function Rn(e){return new URL(e??"/","http://localhost").searchParams.get(en)===tn}async function _n(e,t,n,i,s,o){if(e.method!=="GET"||new URL(e.url??"/","http://localhost").pathname!==n)return!1;let c=i(),l=Rn(e.url)?await o():void 0,a={...c,launch:s,...l?{render:l}:{}};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 kn(e){return{ok:!1,bridgePath:e,runtimeReady:!1,routesIndexed:0,sessionRequired:!0}}function Tn(e){return An(e)?(e.headers["accept-encoding"]="identity",!0):!1}function Pn(e){return Hn(e)?(e.headers["accept-encoding"]="identity",!0):!1}function An(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(ee)||n===Z||n===Ge)return!1;let i=e.headers.accept??"";return i===""||i.includes("text/html")}function Hn(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 Nn(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 l=()=>{if(t.patchNextDevChunk||c)return!1;let a=Buffer.concat(n);if(!/<body\b[^>]*>/iu.test(a.toString("utf8")))return!1;let f=Ve(e,a,t);return f!==a&&!e.headersSent&&e.removeHeader("content-length"),o(f),n.length=0,c=!0,!0};return i.write=(a,f,u)=>c?(a!==void 0&&o(Ie(a,Ee(f))),Y(f),Y(u),!0):(a!==void 0&&(n.push(Ie(a,Ee(f))),l()),Y(f),Y(u),!0),i.end=(a,f,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 f=="function"?r(f):typeof u=="function"?r(u):r():typeof f=="function"?r(S,f):typeof u=="function"?r(S,f,u):r(S,f);S!==void 0&&n.push(Ie(S,Ee(f))),i.write=o,i.end=r,i.flushHeaders=s;let d=Buffer.concat(n),g=Ve(e,d,t);g!==d&&!e.headersSent&&e.removeHeader("content-length");let m=typeof a=="function"?a:typeof f=="function"?f:typeof u=="function"?u:void 0;return m?r(g,m):r(g)},()=>{i.write=o,i.end=r,i.flushHeaders=s}}function Ve(e,t,n){if(On(e,t))return Buffer.from(In(t.toString("utf8"),n));if(n.patchNextDevChunk&&Dn(e)){let i=t.toString("utf8"),s=Bn(i);if(s!==i)return Buffer.from(s)}return t}function Mn(){let e=new Uint8Array(32);return globalThis.crypto.getRandomValues(e),Buffer.from(e).toString("base64url")}function On(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 Dn(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 Bn(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(`
5
5
  `),["unstable_allowPartialStream: true,"," debugChannel,"," startTime: 0"].join(`
6
- `)],[["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])=>jn(n,i,s),e)}function jn(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 Ie(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 Y(e){typeof e=="function"&&e()}async function Un(e){let n=Ve(G(e,"package.json"))(Yt);return n.default??n}function Fn(e){return Le(e)!=="src"?e:xe(Kn(e),"dist")}function Kn(e){return Ye(e)?q.posix.dirname(e):z(e)}function xe(e,t){return Ye(e)?q.posix.join(e,t):G(e,t)}function Ye(e){return e.includes("/")&&!e.includes("\\")}function Wn(e){let t=G(e,".vcp/current-snapshot.json");if(!U(t))return"sandbox_worktree";try{let n=JSON.parse(j(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 $n(e){if(!e)return null;let t=Number.parseInt(e,10);return Number.isInteger(t)&&t>0&&t<=65535?t:null}function Vn(e,t,n){return new Promise((i,s)=>{e.once("error",s),e.listen(t,n,()=>{e.off("error",s),i()})})}function Ln(e){return new Promise(t=>{e.close(()=>t())})}function X(e){try{e()}catch{}}function qn(e){try{return e()}catch(t){return Promise.reject(t)}}function zn(e,t){let n=e.address();return typeof n=="object"&&n?n.port:t}export{ln as attachNextDevUpgradeHandler,ye as attachSiteEditBridgeServerInWorker,vn as classifySiteEditRenderProbeError,mn as createSiteEditAutoBootstrapHtmlSnippet,In as injectSiteEditAutoBootstrap,bn as isSiteEditRenderProbeRequested,Bn as patchNextFirefoxDevChunk,Pn as prepareFirefoxNextDevChunkPatchRequest,kn as prepareSiteEditHtmlInjectionRequest,gn as resolveSiteEditBridgeHealthPath,Qe as resolveSiteEditClientAsset,bi as resolveSiteEditClientAssetPath,un as resolveSiteEditNextDevBundler,Rn as runSiteEditRenderProbe,Ri as startSiteEditNextDevServer,En as transpileSiteEditClientSource};
6
+ `)],[["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])=>jn(n,i,s),e)}function jn(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 Ie(e,t){return Buffer.isBuffer(e)?e:e instanceof Uint8Array?Buffer.from(e):Buffer.from(String(e),t)}function Ee(e){return typeof e=="string"?e:void 0}function Y(e){typeof e=="function"&&e()}async function Un(e){let n=$e(G(e,"package.json"))(Yt);return n.default??n}function Fn(e){return Le(e)!=="src"?e:xe(Kn(e),"dist")}function Kn(e){return Ye(e)?q.posix.dirname(e):z(e)}function xe(e,t){return Ye(e)?q.posix.join(e,t):G(e,t)}function Ye(e){return e.includes("/")&&!e.includes("\\")}function Wn(e){let t=G(e,".vcp/current-snapshot.json");if(!U(t))return"sandbox_worktree";try{let n=JSON.parse(j(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 Vn(e){if(!e)return null;let t=Number.parseInt(e,10);return Number.isInteger(t)&&t>0&&t<=65535?t:null}function $n(e,t,n){return new Promise((i,s)=>{e.once("error",s),e.listen(t,n,()=>{e.off("error",s),i()})})}function Ln(e){return new Promise(t=>{e.close(()=>t())})}function X(e){try{e()}catch{}}function qn(e){try{return e()}catch(t){return Promise.reject(t)}}function zn(e,t){let n=e.address();return typeof n=="object"&&n?n.port:t}export{ln as attachNextDevUpgradeHandler,ye as attachSiteEditBridgeServerInWorker,vn as classifySiteEditRenderProbeError,mn as createSiteEditAutoBootstrapHtmlSnippet,In as injectSiteEditAutoBootstrap,Rn as isSiteEditRenderProbeRequested,Bn as patchNextFirefoxDevChunk,Pn as prepareFirefoxNextDevChunkPatchRequest,Tn as prepareSiteEditHtmlInjectionRequest,gn as resolveSiteEditBridgeHealthPath,Qe as resolveSiteEditClientAsset,Ri as resolveSiteEditClientAssetPath,un as resolveSiteEditNextDevBundler,bn as runSiteEditRenderProbe,bi as startSiteEditNextDevServer,wn as transpileSiteEditClientSource};
package/dist/server.js CHANGED
@@ -1,4 +1,4 @@
1
- import X from"node:http";import R from"node:fs";import{createHash as ee,randomBytes as ye,timingSafeEqual as Ie}from"node:crypto";import f from"node:path";import{WebSocket as te,WebSocketServer as Se}from"ws";import{createPreviewSiteEditEngineRuntime as we,openFileHistoryStore as Ce,resolveManagedPageTemplateComposition as Ee,scanSiteEditCompositionsFromFiles as Re}from"@vcp-dev/site-edit-engine";import{resolveNextAppRouteId as xe,scanNextAppRouterRoutesFromFiles as be}from"@vcp-dev/site-edit-engine/next-app-router";import{SiteEditSourceWatcher as ve}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((a,h)=>[a,h])),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,h)=>a.dynamicDataSummary?[[h,a.dynamicDataSummary]]:[]),u=a=>{let h=e.get(a);if(typeof h=="number")return h;let C=n.length;return n.push(a),e.set(a,C),C},m=a=>{let h=null;for(let C of ce(a)){let V=`${h??"root"}\0${C}`,U=i.get(V);if(typeof U=="number"){h=U;continue}let W=o.length;o.push([h,u(C)]),i.set(V,W),h=W}if(h===null)throw new Error("Document key must not be empty");return h};return{encoding:"segment-trie-v1",siteId:t.siteId,snapshotId:t.snapshotId,composition:{...t.composition},routeId:t.composition.routeId,version:t.version,pageComposition:c,tokens:n,nodes:o,entries:t.entries.map(a=>{let h=a.pageCompositionUnitKey?r.get(a.pageCompositionUnitKey)??-1:-1;if(a.pageCompositionUnitKey&&h<0)throw new Error(`Render entry ${a.key} references unknown page composition unit ${a.pageCompositionUnitKey}`);return[m(a.key),ae(a.operationSummary),...h>=0?[h]:[]]}),...t.entries.every(a=>a.parentKey!==void 0)?{entryParentNodeIds:t.entries.map(a=>a.parentKey===null?null:m(a.parentKey))}:{},...p.length>0?{dynamicDataSummaries:p}:{}}}function ae(t){return(t.canUpdateText?1:0)|(t.canInsertChild?2:0)|(t.canMove?4:0)|(t.canRemove?8:0)}function ce(t){if(!t)return[];let e=[],n=0,i=$(t,n);if(i<0)return e.push(t),e;for(e.push(t.slice(0,i)),n=i;n<t.length;){if(i=$(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 $(t,e){let n=t.indexOf("/",e),i=t.indexOf("::",e);return n<0?i:i<0?n:Math.min(n,i)}var z="SITE_EDIT_COMPOSITION_SESSION_MISMATCH",M="SITE_EDIT_COMPOSITION_SESSION_REQUIRED";var l=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(d(e)&&d(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!d(e)||typeof e.type!="string"?!1:e.type==="request"?ue(e.payload,n):e.type==="response"||e.type==="error"?d(e.payload)&&typeof e.payload.id=="string":e.type==="event"?d(e.payload)&&d(e.payload.event):e.type==="auth"?d(e.payload)&&typeof e.payload.key=="string":e.type==="auth-ok"&&d(e.payload)&&e.payload.ok===!0}},b=class{constructor(e){this.options=e,this.session={subscribedCompositionKeys:new Set},this.messageQueue=new D,this.eventDispatcher=new A(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=_(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:y({...c,data:{...c.data,document:J(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,me(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,y(r,s));return}case"get-style-context":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,y(await this.options.engine.getStyleContext(s),s));return}case"get-object-edit-context":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,y(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,y(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,y(await this.options.engine.getSourceTree(s),s));return}case"get-source-file":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,y(await this.options.engine.getSourceFile({path:i.path,composition:s}),s));return}case"resolve-source-location":{let s=await this.resolveWireContext(i),r=y(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(I(s)!==I(r))throw new S(z,"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=l.extractRequestInfo(e);this.sendJson({type:"error",payload:{...i,message:H(n),code:O(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 S(M,"Initialize a composition session before issuing this request.");if(I(i)!==I(n.context))throw new S(z,"The request composition does not match the active socket session.");return n.context}async resolveWireContext(e){let n=_(e);return this.resolveAndAssert(n)}async resolveOperationWireContext(e){let n=le(e);return this.resolveAndAssert(n)}activateSession(e){this.session.activeComposition=e,this.session.subscribedCompositionKeys.clear(),this.session.subscribedCompositionKeys.add(I(e))}async normalizeOperationRequest(e,n){let i={...e,composition:L(n)};if(i.target.kind==="route"){let o=i.target,s=_(o),r=await this.resolveAndAssert(s);i.target={...o,composition:L(r)}}return i}handleEngineEvent(e){let n=e?.composition;if(!pe(n))return;let i=I(n);this.session.subscribedCompositionKeys.has(i)&&(this.eventDispatcher.push(e),e.type==="site-edit.graph.invalidated"&&i===fe(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(l.parseMessage(e,{validateOperationRequest:this.options.validateOperationRequest}))}catch(n){let i=ge(e);this.sendJson({type:"error",payload:{...i,message:H(n),code:O(n)}})}}sendJson(e){this.options.socket.send(l.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:H(o),code:O(o)}})}finally{this.eventDispatcher.flush()}}},S=class extends Error{constructor(e,n){super(n),this.code=e,this.name="BridgeProtocolError"}},A=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))}},D=class{constructor(e=64){this.maxQueued=e,this.queue=Promise.resolve(),this.queued=0}enqueue(e){if(this.queued>=this.maxQueued)throw new Error("Bridge request queue is full");this.queued+=1;let n=async()=>{this.queued-=1,await e()},i=this.queue.then(n,n);return this.queue=i.then(()=>{},()=>{}),i}};function ue(t,e){if(!d(t)||typeof t.id!="string"||!l.isRequestKind(t.kind))return!1;let n=E(t.composition);switch(t.kind){case"initialize-session":return n&&(t.mutationContext===void 0||T(t.mutationContext));case"get-document":case"get-style-context":return n;case"get-object-edit-context":return typeof t.key=="string"&&n&&de(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&&he(t.request)&&(t.request.mutationContext===void 0||T(t.request.mutationContext))&&(e.validateOperationRequest?.(t.request)??!0);case"undo":case"redo":return n&&t.mutationContext===void 0||n&&T(t.mutationContext)}}function de(t){if(t===void 0)return!0;if(!d(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 he(t){return d(t)&&typeof t.id=="string"&&typeof t.siteId=="string"&&typeof t.baseSnapshotId=="string"&&E(t.composition)&&typeof t.kind=="string"&&d(t.target)&&(t.target.kind!=="route"||E(t.target.composition))&&typeof t.documentVersion=="number"&&Number.isInteger(t.documentVersion)&&t.documentVersion>=0&&d(t.params)}function E(t){return d(t)&&typeof t.routeId=="string"&&t.routeId.length>0&&(t.templateId===void 0||typeof t.templateId=="string"&&t.templateId.length>0)&&Object.keys(t).every(e=>e==="routeId"||e==="templateId")}function pe(t){return d(t)&&typeof t.routeId=="string"&&(t.effectiveTemplateId===void 0||typeof t.effectiveTemplateId=="string")}function _(t){if(E(t.composition))return t.composition;throw new S(M,"A composition selector is required for this request.")}function le(t){if(d(t)&&E(t.composition))return t.composition;throw new S(M,"A composition selector is required for execute.")}function L(t){return{routeId:t.routeId,...t.effectiveTemplateId?{templateId:t.effectiveTemplateId}:{}}}function fe(t){return t.activeComposition?I(t.activeComposition):null}function I(t){return JSON.stringify([t.routeId,t.effectiveTemplateId??null])}function y(t,e){return d(t)&&t.ok===!0?{...t,composition:e}:t}function me(t,e){return!d(t)||t.ok!==!0?t:{...t,...e?{composition:e}:{},data:J(t.data)}}function J(t){let e=t;return j(e.routeId?e:{...e,routeId:e.composition.routeId})}function d(t){return typeof t=="object"&&t!==null}function T(t){return d(t)&&typeof t.editingSessionId=="string"&&t.editingSessionId.length>0&&typeof t.lockId=="string"&&t.lockId.length>0&&typeof t.ownerId=="string"&&t.ownerId.length>0&&typeof t.leaseAssertion=="string"&&t.leaseAssertion.length>0}function O(t){if(!(!d(t)||typeof t.code!="string"||t.code.length===0))return t.code}function H(t){return t instanceof Error||d(t)&&typeof t.message=="string"&&t.message.length>0?t.message:"Unknown websocket operation failure"}function ge(t){try{return l.extractRequestInfo(JSON.parse(t))}catch{return{id:"unknown",kind:"get-document"}}}var v=class{constructor(){this.tail=Promise.resolve()}run(e){let n=this.tail.then(e,e);return this.tail=n.then(()=>{},()=>{}),n}};import{SiteEditOperationRequestSchema as ke,computeSiteEditCompositionKey as w}from"@vcp-dev/contracts";var _e="127.0.0.1",Te=30218,Oe="/__vcp/site-edit/bridge",ne=6*1024*1024,He=ne*2,Ae=3e3,Q=50,K=".vcp/current-snapshot.json",G="__VCP_SITE_EDIT_BRIDGE_SERVERS__";function at(t){let e=k(t),n=se(e),i=ie(),o=i.get(n);if(o)return o;let s=new x(e);i.set(n,s);try{s.start()}catch(r){throw i.delete(n),s.stop(),r}return s}function ct(t,e,n={}){let i=new x(k(e),t,!1,n);return i.start({listen:!1}),i}var x=class{constructor(e,n=X.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 v,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{R.mkdirSync(f.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=Ke({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 ve({projectRoot:this.options.projectRoot,watch_dirs:De(this.options.runtime.watch_dirs),interval_ms:this.options.runtime.watch_interval_ms,debounce_ms:this.options.runtime.watch_debounce_ms??Q,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=ie(),n=se(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??we)({...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=Fe(e.composition),o=this.getRuntime(),s=g(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=g(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(g(e)),getObjectEditContext:async(e,n,i)=>this.getRuntime().getObjectEditContext(e,g(n),i),getClassNameSource:async(e,n)=>this.getRuntime().getClassNameSource(e,g(n)),getSourceTree:async e=>this.getRuntime().getSourceTree(g(e)),getSourceFile:async e=>this.getRuntime().getSourceFile({path:e.path,composition:g(e.composition)}),resolveSourceLocation:async e=>this.getRuntime().resolveSourceLocation({key:e.key,composition:g(e.composition)}),execute:(e,n)=>this.mutationQueue.run(async()=>{let i=await this.bindHistorySession(this.options.snapshotId);if(!i.ok)return F(i,e);let o=await this.getRuntime().executeOperation(e);return o.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(o.data.resultVersion,o.composition),o}),undo:e=>this.mutationQueue.run(async()=>{let n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)return F(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 F(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??Ce)(Be({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=w(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?w(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??Q;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(je)&&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=R.readFileSync(f.join(this.options.projectRoot,K),"utf8"),n=JSON.parse(e),i=typeof n.snapshot_id=="string"?n.snapshot_id:"";return!i||N(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=Me(this.options.projectRoot),i=be(n),o=i.length>0?i:(this.options.runtime.routes??[]).map(u=>({...u})),s=Re({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=>[w(u.context),u])),p=new Map(s.map(u=>[w(u.context),u]));if(this.runtime){for(let[u,m]of c){let a=p.get(u);(!a||a.entryFile!==m.entryFile)&&this.runtime.unregisterComposition(g(m.context))}for(let[u,m]of p){let a=c.get(u);(!a||a.entryFile!==m.entryFile)&&this.runtime.registerComposition(m.context,m.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=xe(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=Ee({selector:{routeId:n,...e.templateId!==void 0?{templateId:e.templateId}:{}},files:this.compositionFiles,canonicalEntryFile:i.entryFile}),s=w(o.context);if(!this.compositions.some(r=>w(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(w(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 ut(t){let e=new x(k(t),X.createServer(),!1);return e.start({listen:!1,webSocket:!1}),{engine:e.getEngine(),getHealth:()=>e.getHealth(),stop:()=>e.stop()}}function dt(t){return k(t)}function k(t){return{tenantId:t.tenantId,siteId:t.siteId,snapshotId:t.snapshotId,projectRoot:f.resolve(t.projectRoot??process.cwd()),basePath:t.basePath??"",host:t.host??_e,port:t.port??Te,path:t.path??Oe,sessionKey:t.sessionKey??$e(),historyRoot:t.historyRoot,allowedOrigins:t.allowedOrigins??[],runtime:t.runtime??{},onSnapshotIdChanged:t.onSnapshotIdChanged,onHealthChanged:t.onHealthChanged}}function De(t){let e=["app","src/app","components/site","src/components/site","lib/generated","src/lib/generated","public"];return[...new Set([...t?.length?t:e,".vcp"])]}function Me(t){let e=[],n=["app","src/app",".vcp"],i=new Set([".git",".next",".turbo","coverage","dist","node_modules","output","snapshot-store"]),o=s=>{if(!R.existsSync(s))return;let r;try{r=R.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(f.join(s,c.name));continue}if(!c.isFile())continue;let p=f.join(s,c.name),u="";try{u=R.readFileSync(p,"utf8")}catch{}e.push({path:f.relative(t,p).replaceAll(f.sep,"/"),content:u})}};for(let s of n)o(f.join(t,s));return e.sort((s,r)=>s.path.localeCompare(r.path))}function Fe(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 g(t){return{routeId:t.routeId,...t.effectiveTemplateId?{templateId:t.effectiveTemplateId}:{}}}function Be(t){return f.join(f.resolve(t.root),N(t.siteId),N(t.snapshotId),ee("sha256").update(t.editingSessionId).digest("hex").slice(0,32))}function N(t){return/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(t)&&t!=="."&&t!==".."?t:ee("sha256").update(t).digest("hex").slice(0,32)}function ie(){let t=globalThis;return t[G]??=new Map,t[G]}function se(t){return`${t.projectRoot}:${t.host}:${t.port}:${t.path}:${t.historyRoot??""}`}function F(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 Ke(t){let e=new Se({maxPayload:ne,noServer:!0}),n=new WeakSet,i=s=>{new b({socket:new P(s),engine:t.engine,validateOperationRequest:r=>ke.safeParse(r).success})},o=(s,r,c)=>{if(!Ne(s,t))return;let p=Pe(s,t);if(!p){r.write(`HTTP/1.1 401 Unauthorized\r
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
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}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 P=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===te.OPEN){if(this.socket.bufferedAmount+Buffer.byteLength(e,"utf8")>He){this.socket.close(1013,"bridge backpressure");return}this.socket.send(e)}}close(e,n){this.socket.close(e,n)}};function Ne(t,e){return new URL(t.url??"/","http://localhost").pathname===e.path}function Pe(t,e){if(new URL(t.url??"/","http://localhost").searchParams.has("vcp_bridge_key"))return null;let i=B(t.headers["x-vcp-site-edit-key"]),o=oe(i,e.sessionKey),s=B(t.headers.host),r=B(t.headers.origin);return s&&!Ve(s,e.host,r)?null:r?We(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")},Ae),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=l.parseMessage(c.toString());if(p.type!=="auth"||!oe(p.payload.key,e)){r();return}s(),t.readyState===te.OPEN&&t.send(l.stringifyMessage({type:"auth-ok",payload:{ok:!0}})),n()}catch{r()}},t.on("message",o),t.on("close",s)}function oe(t,e){if(!t)return!1;let n=Buffer.from(t),i=Buffer.from(e);return n.length===i.length&&Ie(n,i)}function Ve(t,e,n){let i=Z(t),o=Z(e);return i===o||Y(o)&&Y(i)&&(!n||q(n,t))||Ue(o)&&(!n||q(n,t))}function Ue(t){return t==="0.0.0.0"||t==="::"}function Y(t){return t==="localhost"||t==="127.0.0.1"||t==="::1"}function We(t,e,n){return n.includes(t)||(e?q(t,e):!1)}function q(t,e){try{return new URL(t).host===re(e)}catch{return!1}}function Z(t){let e=re(t);return e.startsWith("[")?e.slice(1,e.indexOf("]")):e.split(":").length-1===1?e.split(":",1)[0]??"":e}function re(t){return t.trim().toLowerCase()}function B(t){return Array.isArray(t)?t[0]:t}function $e(){return ye(32).toString("base64url")}function je(t){let e=t.replaceAll("\\","/");return e===K||e.endsWith(`/${K}`)}export{He as SITE_EDIT_BRIDGE_MAX_BUFFERED_BYTES,ne as SITE_EDIT_BRIDGE_MAX_PAYLOAD_BYTES,x as SiteEditBridgeServer,ct as attachSiteEditBridgeServer,Ke as attachSiteEditWebSocketServer,ut as createSiteEditBridgeEngineHost,at as ensureSiteEditBridgeServerStarted,dt as normalizeSiteEditBridgeServerOptions};
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};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcp-dev/site-edit-bridge",
3
- "version": "0.10.22",
3
+ "version": "0.10.24",
4
4
  "type": "module",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -79,8 +79,8 @@
79
79
  "typecheck": "tsc -p tsconfig.json --noEmit"
80
80
  },
81
81
  "dependencies": {
82
- "@vcp-dev/contracts": "0.10.22",
83
- "@vcp-dev/site-edit-engine": "0.10.22",
82
+ "@vcp-dev/contracts": "0.10.24",
83
+ "@vcp-dev/site-edit-engine": "0.10.24",
84
84
  "@types/ws": "^8.18.1",
85
85
  "ws": "^8.20.1"
86
86
  },