@vcp-dev/site-edit-bridge 0.10.35 → 0.10.36

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