@vcp-dev/site-edit-bridge 0.8.5 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
- import ae from"node:http";import{existsSync as _,readFileSync as v}from"node:fs";import{randomUUID as Pt}from"node:crypto";import{createRequire as He}from"node:module";import{Socket as Te}from"node:net";import k from"node:path";import{basename as Be,dirname as P,join as H}from"node:path";import{fileURLToPath as Ae}from"node:url";import Ze from"node:http";import Z from"node:fs";import{createHash as Ce,randomBytes as Xe,timingSafeEqual as et}from"node:crypto";import x from"node:path";import{WebSocket as Re,WebSocketServer as tt}from"ws";import{createPreviewSiteEditEngineRuntime as nt,openFileHistoryStore as it,resolveManagedPageTemplateComposition as ot,scanSiteEditCompositionsFromFiles as st}from"@vcp-dev/site-edit-engine";import{resolveNextAppRouteId as rt,scanNextAppRouterRoutesFromFiles as at}from"@vcp-dev/site-edit-engine/next-app-router";import{SiteEditSourceWatcher as ct}from"@vcp-dev/site-edit-engine/source-watcher";function fe(e){let t=new Map,n=[],i=new Map,s=[],o=e.pageComposition.status==="supported"?e.pageComposition.placementUnitKeys:[],r=new Map(o.map((d,p)=>[d,p])),u=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},c=e.entries.flatMap((d,p)=>d.dynamicDataSummary?[[p,d.dynamicDataSummary]]:[]),a=d=>{let p=t.get(d);if(typeof p=="number")return p;let l=n.length;return n.push(d),t.set(d,l),l},h=d=>{let p=null;for(let l of We(d)){let y=`${p??"root"}\0${l}`,S=i.get(y);if(typeof S=="number"){p=S;continue}let I=s.length;s.push([p,a(l)]),i.set(y,I),p=I}if(p===null)throw new Error("Document key must not be empty");return p};return{encoding:"segment-trie-v1",siteId:e.siteId,snapshotId:e.snapshotId,composition:{...e.composition},routeId:e.composition.routeId,version:e.version,pageComposition:u,tokens:n,nodes:s,entries:e.entries.map(d=>{let p=d.pageCompositionUnitKey?r.get(d.pageCompositionUnitKey)??-1:-1;if(d.pageCompositionUnitKey&&p<0)throw new Error(`Render entry ${d.key} references unknown page composition unit ${d.pageCompositionUnitKey}`);return[h(d.key),qe(d.operationSummary),...p>=0?[p]:[]]}),...c.length>0?{dynamicDataSummaries:c}:{}}}function qe(e){return(e.canUpdateText?1:0)|(e.canInsertChild?2:0)|(e.canMove?4:0)|(e.canRemove?8:0)}function We(e){if(!e)return[];let t=[],n=0,i=pe(e,n);if(i<0)return t.push(e),t;for(t.push(e.slice(0,i)),n=i;n<e.length;){if(i=pe(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 pe(e,t){let n=e.indexOf("/",t),i=e.indexOf("::",t);return n<0?i:i<0?n:Math.min(n,i)}var le="SITE_EDIT_COMPOSITION_SESSION_MISMATCH",Y="SITE_EDIT_COMPOSITION_SESSION_REQUIRED";var m=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(f(t)&&f(t.payload)){let n=typeof t.payload.id=="string"?t.payload.id:"unknown",i=this.isRequestKind(t.payload.kind)?t.payload.kind:"get-document";return{id:n,kind:i}}return{id:"unknown",kind:"get-document"}}static isRequestKind(t){return t==="initialize-session"||t==="get-document"||t==="get-history-status"||t==="get-style-context"||t==="get-object-edit-context"||t==="get-class-name-source"||t==="get-source-tree"||t==="get-source-file"||t==="resolve-source-location"||t==="execute"||t==="undo"||t==="redo"}static isMessage(t,n={}){return!f(t)||typeof t.type!="string"?!1:t.type==="request"?Le(t.payload,n):t.type==="response"||t.type==="error"?f(t.payload)&&typeof t.payload.id=="string":t.type==="event"?f(t.payload)&&f(t.payload.event):t.type==="auth"?f(t.payload)&&typeof t.payload.key=="string":t.type==="auth-ok"&&f(t.payload)&&t.payload.ok===!0}},M=class{constructor(t){this.options=t,this.session={subscribedCompositionKeys:new Set},this.messageQueue=new Q,this.eventDispatcher=new G(n=>{this.sendJson(n)}),this.unsubscribe=t.engine.subscribe(n=>{this.handleEngineEvent(n)}),t.socket.onmessage=n=>{try{this.messageQueue.enqueue(()=>this.handleRawMessage(n.data))}catch(i){this.sendJson({type:"error",payload:{id:"unknown",kind:"get-document",message:i instanceof Error?i.message:"Bridge queue overflow"}}),t.socket.close(1013,"bridge busy")}},t.socket.onclose=()=>{this.unsubscribe(),this.session.activeComposition=void 0,this.session.subscribedCompositionKeys.clear()}}async handleMessage(t){try{let n=t;if(n.type!=="request")return;let i=n.payload,{id:s}=i;switch(i.kind){case"initialize-session":{let o=L(i),r=await this.resolve(o),u=await this.options.engine.initializeSession({composition:r.context,...i.mutationContext?{mutationContext:i.mutationContext}:{}});this.activateSession(r.context),this.sendJson({type:"response",payload:{id:s,kind:i.kind,result:w({...u,data:{...u.data,document:ge(u.data.document)}},r.context)}});return}case"get-document":{let o=await this.resolveWireContext(i),r=await this.options.engine.getDocument(o);this.sendResult(s,i.kind,Qe(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,w(r,o));return}case"get-style-context":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,w(await this.options.engine.getStyleContext(o),o));return}case"get-object-edit-context":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,w(await this.options.engine.getObjectEditContext(i.key,o),o));return}case"get-class-name-source":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,w(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,w(await this.options.engine.getSourceTree(o),o));return}case"get-source-file":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,w(await this.options.engine.getSourceFile({path:i.path,composition:o}),o));return}case"resolve-source-location":{let o=await this.resolveWireContext(i),r=w(await this.options.engine.resolveSourceLocation({key:i.key,composition:o}),o);this.sendResult(s,i.kind,r);return}case"execute":{let o=await this.resolveOperationWireContext(i.request),r=await this.resolveWireContext(i);if(C(o)!==C(r))throw new R(le,"The execute request composition does not match its operation composition.");let u=await this.normalizeOperationRequest(i.request,o);await this.handleBufferedOperation(s,i.kind,()=>this.options.engine.execute(u));return}case"undo":case"redo":{let o=await this.resolveWireContext(i);await this.handleBufferedOperation(s,i.kind,()=>i.kind==="undo"?this.options.engine.undo(o):this.options.engine.redo(o));return}}}catch(n){let i=m.extractRequestInfo(t);this.sendJson({type:"error",payload:{...i,message:J(n),code:z(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 R(Y,"Initialize a composition session before issuing this request.");if(C(i)!==C(n.context))throw new R(le,"The request composition does not match the active socket session.");return n.context}async resolveWireContext(t){let n=L(t);return this.resolveAndAssert(n)}async resolveOperationWireContext(t){let n=Je(t);return this.resolveAndAssert(n)}activateSession(t){this.session.activeComposition=t,this.session.subscribedCompositionKeys.clear(),this.session.subscribedCompositionKeys.add(C(t))}async normalizeOperationRequest(t,n){let i={...t,composition:me(n)};if(i.target.kind==="route"){let s=i.target,o=L(s),r=await this.resolveAndAssert(o);i.target={...s,composition:me(r)}}return i}handleEngineEvent(t){let n=t?.composition;if(!ze(n))return;let i=C(n);this.session.subscribedCompositionKeys.has(i)&&(this.eventDispatcher.push(t),t.type==="site-edit.graph.invalidated"&&i===Ge(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(m.parseMessage(t,{validateOperationRequest:this.options.validateOperationRequest}))}catch(n){let i=Ye(t);this.sendJson({type:"error",payload:{...i,message:J(n),code:z(n)}})}}sendJson(t){this.options.socket.send(m.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:J(s),code:z(s)}})}finally{this.eventDispatcher.flush()}}},R=class extends Error{constructor(t,n){super(n),this.code=t,this.name="BridgeProtocolError"}},G=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))}},Q=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 Le(e,t){if(!f(e)||typeof e.id!="string"||!m.isRequestKind(e.kind))return!1;let n=T(e.composition);switch(e.kind){case"initialize-session":return n&&(e.mutationContext===void 0||$(e.mutationContext));case"get-document":case"get-style-context":return n;case"get-object-edit-context":case"get-class-name-source":case"resolve-source-location":return typeof e.key=="string"&&n;case"get-history-status":return n;case"get-source-tree":return n;case"get-source-file":return typeof e.path=="string"&&n;case"execute":return n&&$e(e.request)&&(e.request.mutationContext===void 0||$(e.request.mutationContext))&&(t.validateOperationRequest?.(e.request)??!0);case"undo":case"redo":return n&&e.mutationContext===void 0||n&&$(e.mutationContext)}}function $e(e){return f(e)&&typeof e.id=="string"&&typeof e.siteId=="string"&&typeof e.baseSnapshotId=="string"&&T(e.composition)&&typeof e.kind=="string"&&f(e.target)&&(e.target.kind!=="route"||T(e.target.composition))&&typeof e.documentVersion=="number"&&Number.isInteger(e.documentVersion)&&e.documentVersion>=0&&f(e.params)}function T(e){return f(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 ze(e){return f(e)&&typeof e.routeId=="string"&&(e.effectiveTemplateId===void 0||typeof e.effectiveTemplateId=="string")}function L(e){if(T(e.composition))return e.composition;throw new R(Y,"A composition selector is required for this request.")}function Je(e){if(f(e)&&T(e.composition))return e.composition;throw new R(Y,"A composition selector is required for execute.")}function me(e){return{routeId:e.routeId,...e.effectiveTemplateId?{templateId:e.effectiveTemplateId}:{}}}function Ge(e){return e.activeComposition?C(e.activeComposition):null}function C(e){return JSON.stringify([e.routeId,e.effectiveTemplateId??null])}function w(e,t){return f(e)&&e.ok===!0?{...e,composition:t}:e}function Qe(e,t){return!f(e)||e.ok!==!0?e:{...e,...t?{composition:t}:{},data:ge(e.data)}}function ge(e){let t=e;return fe(t.routeId?t:{...t,routeId:t.composition.routeId})}function f(e){return typeof e=="object"&&e!==null}function $(e){return f(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 z(e){if(!(!f(e)||typeof e.code!="string"||e.code.length===0))return e.code}function J(e){return e instanceof Error||f(e)&&typeof e.message=="string"&&e.message.length>0?e.message:"Unknown websocket operation failure"}function Ye(e){try{return m.extractRequestInfo(JSON.parse(e))}catch{return{id:"unknown",kind:"get-document"}}}var N=class{constructor(){this.tail=Promise.resolve()}run(t){let n=this.tail.then(t,t);return this.tail=n.then(()=>{},()=>{}),n}};import{SiteEditOperationRequestSchema as ut,computeSiteEditCompositionKey as b}from"@vcp-dev/contracts";var dt="127.0.0.1",ht=30218,pt="/__vcp/site-edit/bridge",be=6*1024*1024,ft=be*2,lt=3e3,ye=50,Se="__VCP_SITE_EDIT_BRIDGE_SERVERS__";function Ee(e,t,n={}){let i=new te(mt(t),e,!1,n);return i.start({listen:!1}),i}var te=class{constructor(t,n=Ze.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 N,this.eventListeners=new Set,this.routes=[],this.compositions=[],this.compositionFiles=[],this.compositionResolutionError=null,this.stopWatching=null,this.stopWebSocketServer=null,this.pendingChangedFiles=new Set,this.fileChangeTimer=null,this.isStarted=!1,this.runtimeVersionFloors=new Map,this.activeHistoryStore=null,this.versionPersistence=Promise.resolve()}start(t={}){if(this.isStarted)return;this.refreshCompositions(!0),this.isStarted=!0,this.createRuntime();let n=Ct({server:this.server,path:this.options.path,sessionKey:this.options.sessionKey,host:this.options.host,allowedOrigins:this.options.allowedOrigins,engine:this.createBridgeEngine()});this.stopWebSocketServer=n.stop,this.stopWatching=new ct({projectRoot:this.options.projectRoot,watch_dirs:gt(this.options.runtime.watch_dirs),interval_ms:this.options.runtime.watch_interval_ms,debounce_ms:this.options.runtime.watch_debounce_ms??ye,max_dirs:this.options.runtime.watch_max_dirs,max_files:this.options.runtime.watch_max_files,max_depth:this.options.runtime.watch_max_depth,max_startup_ms:this.options.runtime.watch_max_startup_ms,on_change:i=>this.handleFileChanged(i),on_batch_change:i=>this.handleFilesChanged(i)}).start(),t.listen!==!1&&this.server.listen(this.options.port,this.options.host)}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.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=wt(),n=xt(this.options);t.get(n)===this&&t.delete(n),this.isStarted=!1}createRuntime(t,n=null){let i=this.runtime;this.activeHistoryStore=t??null;let s=(this.dependencies.createRuntime??nt)({...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()}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=St(t.composition),s=this.getRuntime(),o=g(i);await s.initializeComposition(o);let u=s.getDocument(o).data;await this.recordRuntimeVersion(u.version,i);let c=(await s.getHistoryStatus()).data;return{ok:!0,composition:i,data:{document:u,historyStatus:c}}}),getDocument:async t=>{let n=this.getRuntime(),i=g(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(g(t)),getObjectEditContext:async(t,n)=>this.getRuntime().getObjectEditContext(t,g(n)),getClassNameSource:async(t,n)=>this.getRuntime().getClassNameSource(t,g(n)),getSourceTree:async t=>this.getRuntime().getSourceTree(g(t)),getSourceFile:async t=>this.getRuntime().getSourceFile({path:t.path,composition:g(t.composition)}),resolveSourceLocation:async t=>this.getRuntime().resolveSourceLocation({key:t.key,composition:g(t.composition)}),execute:(t,n)=>this.mutationQueue.run(async()=>{let i=await this.bindHistorySession(this.options.snapshotId);if(!i.ok)return X(i,t);let s=await this.getRuntime().executeOperation(t);return s.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(s.data.resultVersion,s.composition),s}),undo:t=>this.mutationQueue.run(async()=>{let n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)return X(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 X(n,void 0,t);let i=await this.getRuntime().redo();return i.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(i.data.resultVersion,i.composition??t),i.composition?i:{...i,composition:t}}),subscribe:t=>(this.eventListeners.add(t),()=>this.eventListeners.delete(t))}}async bindHistorySession(t){if(!this.options.historyRoot)return{ok:!1,code:"RECOVERY_PERSIST_FAILED",message:"Durable edit history is not configured."};if(this.activeHistorySessionId===t)return{ok:!0};let n=this.historySessionTransition.then(async()=>{if(this.activeHistorySessionId===t)return;let i=await(this.dependencies.openHistoryStore??it)(It({root:this.options.historyRoot,siteId:this.options.siteId,snapshotId:this.options.snapshotId,editingSessionId:t}));if(!this.isStarted)return;let s=i.readDocumentVersion?await i.readDocumentVersion():0,o=this.compositions[0]?.context;if(o){let r=b(o);this.runtimeVersionFloors.set(r,Math.max(this.runtimeVersionFloors.get(r)??0,s))}this.createRuntime(i,t)});this.historySessionTransition=n.catch(()=>{});try{return await n,{ok:!0}}catch{return{ok:!1,code:"RECOVERY_PERSIST_FAILED",message:"Durable edit history could not be opened."}}}recordRuntimeVersion(t,n){let i=n?b(n):null;i&&this.runtimeVersionFloors.set(i,Math.max(this.runtimeVersionFloors.get(i)??0,t));let s=this.activeHistoryStore;if(!s?.writeDocumentVersion)return Promise.resolve();let o=i?this.runtimeVersionFloors.get(i)??t:t;return this.versionPersistence=this.versionPersistence.then(()=>s.writeDocumentVersion(o)).catch(()=>{}),this.versionPersistence}handleFileChanged(t){this.handleFilesChanged([t])}handleFilesChanged(t){for(let i of t)this.pendingChangedFiles.add(i);this.fileChangeTimer&&clearTimeout(this.fileChangeTimer);let n=this.options.runtime.watch_debounce_ms??ye;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(),!!this.refreshCompositions(!1))for(let n of t)this.runtime?.notifyFileChanged(n)}refreshCompositions(t=!1){try{let n=yt(this.options.projectRoot),i=at(n),s=i.length>0?i:(this.options.runtime.routes??[]).map(c=>({...c})),o=st({files:n});if(o.length===0)throw new Error("No canonical App Router composition is indexed by the preview bridge.");let r=new Map(this.compositions.map(c=>[b(c.context),c])),u=new Map(o.map(c=>[b(c.context),c]));if(this.runtime){for(let[c,a]of r){let h=u.get(c);(!h||h.entryFile!==a.entryFile)&&this.runtime.unregisterComposition(g(a.context))}for(let[c,a]of u){let h=r.get(c);(!h||h.entryFile!==a.entryFile)&&this.runtime.registerComposition(a.context,a.entryFile)}}return this.routes=s,this.compositions=o,this.compositionFiles=n,this.compositionResolutionError=null,!0}catch(n){let i=n instanceof Error?n:new Error(String(n));if(this.compositionResolutionError=i,t)throw i;return!1}}resolveComposition(t){if(this.compositionResolutionError)throw this.compositionResolutionError;let n=rt(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=ot({selector:{routeId:n,...t.templateId?{templateId:t.templateId}:{}},files:this.compositionFiles,canonicalEntryFile:i.entryFile}),o=b(s.context);if(!this.compositions.some(r=>b(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(b(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 mt(e){return{tenantId:e.tenantId,siteId:e.siteId,snapshotId:e.snapshotId,projectRoot:x.resolve(e.projectRoot??process.cwd()),basePath:e.basePath??"",host:e.host??dt,port:e.port??ht,path:e.path??pt,sessionKey:e.sessionKey??kt(),historyRoot:e.historyRoot,allowedOrigins:e.allowedOrigins??[],runtime:e.runtime??{}}}function gt(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 yt(e){let t=[],n=["app","src/app",".vcp"],i=new Set([".git",".next",".turbo","coverage","dist","node_modules","output","snapshot-store"]),s=o=>{if(!Z.existsSync(o))return;let r;try{r=Z.readdirSync(o,{withFileTypes:!0})}catch{return}for(let u of r){if(u.name.startsWith(".")&&u.name!==".vcp")continue;if(u.isDirectory()){if(i.has(u.name))continue;s(x.join(o,u.name));continue}if(!u.isFile())continue;let c=x.join(o,u.name),a="";try{a=Z.readFileSync(c,"utf8")}catch{}t.push({path:x.relative(e,c).replaceAll(x.sep,"/"),content:a})}};for(let o of n)s(x.join(e,o));return t.sort((o,r)=>o.path.localeCompare(r.path))}function St(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 g(e){return{routeId:e.routeId,...e.effectiveTemplateId?{templateId:e.effectiveTemplateId}:{}}}function It(e){return x.join(x.resolve(e.root),Ie(e.siteId),Ie(e.snapshotId),Ce("sha256").update(e.editingSessionId).digest("hex").slice(0,32))}function Ie(e){return/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(e)&&e!=="."&&e!==".."?e:Ce("sha256").update(e).digest("hex").slice(0,32)}function wt(){let e=globalThis;return e[Se]??=new Map,e[Se]}function xt(e){return`${e.projectRoot}:${e.host}:${e.port}:${e.path}:${e.historyRoot??""}`}function X(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 Ct(e){let t=new tt({maxPayload:be,noServer:!0}),n=new WeakSet,i=o=>{new M({socket:new ne(o),engine:e.engine,validateOperationRequest:r=>ut.safeParse(r).success})},s=(o,r,u)=>{if(!Rt(o,e))return;let c=bt(o,e);if(!c){r.write(`HTTP/1.1 401 Unauthorized\r
1
+ import ut from"node:http";import{existsSync as _,readFileSync as b}from"node:fs";import{randomUUID as Ae}from"node:crypto";import{createRequire as Bt}from"node:module";import{Socket as Pt}from"node:net";import H from"node:path";import{basename as Dt,dirname as A,join as B}from"node:path";import{fileURLToPath as Ot}from"node:url";import Xt from"node:http";import P from"node:fs";import{createHash as Rt,randomBytes as te,timingSafeEqual as ee}from"node:crypto";import g from"node:path";import{WebSocket as Et,WebSocketServer as ne}from"ws";import{createPreviewSiteEditEngineRuntime as se,openFileHistoryStore as oe,resolveManagedPageTemplateComposition as ie,scanSiteEditCompositionsFromFiles as re}from"@vcp-dev/site-edit-engine";import{resolveNextAppRouteId as ae,scanNextAppRouterRoutesFromFiles as ce}from"@vcp-dev/site-edit-engine/next-app-router";import{SiteEditSourceWatcher as ue}from"@vcp-dev/site-edit-engine/source-watcher";function gt(t){let e=new Map,n=[],s=new Map,o=[],i=t.pageComposition.status==="supported"?t.pageComposition.placementUnitKeys:[],r=new Map(i.map((d,p)=>[d,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(d=>({placementKey:d.placementKey,placementUnitKey:d.placementUnitKey,relation:d.relation}))}:{status:"unsupported",reason:t.pageComposition.reason,diagnostics:t.pageComposition.diagnostics},u=t.entries.flatMap((d,p)=>d.dynamicDataSummary?[[p,d.dynamicDataSummary]]:[]),c=d=>{let p=e.get(d);if(typeof p=="number")return p;let l=n.length;return n.push(d),e.set(d,l),l},h=d=>{let p=null;for(let l of Wt(d)){let S=`${p??"root"}\0${l}`,I=s.get(S);if(typeof I=="number"){p=I;continue}let w=o.length;o.push([p,c(l)]),s.set(S,w),p=w}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(d=>{let p=d.pageCompositionUnitKey?r.get(d.pageCompositionUnitKey)??-1:-1;if(d.pageCompositionUnitKey&&p<0)throw new Error(`Render entry ${d.key} references unknown page composition unit ${d.pageCompositionUnitKey}`);return[h(d.key),$t(d.operationSummary),...p>=0?[p]:[]]}),...u.length>0?{dynamicDataSummaries:u}:{}}}function $t(t){return(t.canUpdateText?1:0)|(t.canInsertChild?2:0)|(t.canMove?4:0)|(t.canRemove?8:0)}function Wt(t){if(!t)return[];let e=[],n=0,s=mt(t,n);if(s<0)return e.push(t),e;for(e.push(t.slice(0,s)),n=s;n<t.length;){if(s=mt(t,n+(t.startsWith("::",n)?2:1)),s<0){e.push(t.slice(n));break}e.push(t.slice(n,s)),n=s}return e}function mt(t,e){let n=t.indexOf("/",e),s=t.indexOf("::",e);return n<0?s:s<0?n:Math.min(n,s)}var yt="SITE_EDIT_COMPOSITION_SESSION_MISMATCH",Z="SITE_EDIT_COMPOSITION_SESSION_REQUIRED";var m=class t{constructor(){}static parseMessage(e,n={}){let s=JSON.parse(e);if(!t.isMessage(s,n))throw new Error("Invalid site edit bridge message");return s}static stringifyMessage(e){return JSON.stringify(e)}static extractRequestInfo(e){if(f(e)&&f(e.payload)){let n=typeof e.payload.id=="string"?e.payload.id:"unknown",s=this.isRequestKind(e.payload.kind)?e.payload.kind:"get-document";return{id:n,kind:s}}return{id:"unknown",kind:"get-document"}}static isRequestKind(e){return e==="initialize-session"||e==="get-document"||e==="get-history-status"||e==="get-style-context"||e==="get-object-edit-context"||e==="get-class-name-source"||e==="get-source-tree"||e==="get-source-file"||e==="resolve-source-location"||e==="execute"||e==="undo"||e==="redo"}static isMessage(e,n={}){return!f(e)||typeof e.type!="string"?!1:e.type==="request"?Lt(e.payload,n):e.type==="response"||e.type==="error"?f(e.payload)&&typeof e.payload.id=="string":e.type==="event"?f(e.payload)&&f(e.payload.event):e.type==="auth"?f(e.payload)&&typeof e.payload.key=="string":e.type==="auth-ok"&&f(e.payload)&&e.payload.ok===!0}},j=class{constructor(e){this.options=e,this.session={subscribedCompositionKeys:new Set},this.messageQueue=new Y,this.eventDispatcher=new Q(n=>{this.sendJson(n)}),this.unsubscribe=e.engine.subscribe(n=>{this.handleEngineEvent(n)}),e.socket.onmessage=n=>{try{this.messageQueue.enqueue(()=>this.handleRawMessage(n.data))}catch(s){this.sendJson({type:"error",payload:{id:"unknown",kind:"get-document",message:s instanceof Error?s.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 s=n.payload,{id:o}=s;switch(s.kind){case"initialize-session":{let i=L(s),r=await this.resolve(i),a=await this.options.engine.initializeSession({composition:r.context,...s.mutationContext?{mutationContext:s.mutationContext}:{}});this.activateSession(r.context),this.sendJson({type:"response",payload:{id:o,kind:s.kind,result:x({...a,data:{...a.data,document:It(a.data.document)}},r.context)}});return}case"get-document":{let i=await this.resolveWireContext(s),r=await this.options.engine.getDocument(i);this.sendResult(o,s.kind,Yt(r,i));return}case"get-history-status":{let i=await this.resolveWireContext(s),r=await this.options.engine.getHistoryStatus(i);this.sendResult(o,s.kind,x(r,i));return}case"get-style-context":{let i=await this.resolveWireContext(s);this.sendResult(o,s.kind,x(await this.options.engine.getStyleContext(i),i));return}case"get-object-edit-context":{let i=await this.resolveWireContext(s);this.sendResult(o,s.kind,x(await this.options.engine.getObjectEditContext(s.key,i),i));return}case"get-class-name-source":{let i=await this.resolveWireContext(s);this.sendResult(o,s.kind,x(await this.options.engine.getClassNameSource(s.key,i),i));return}case"get-source-tree":{let i=await this.resolveWireContext(s);this.sendResult(o,s.kind,x(await this.options.engine.getSourceTree(i),i));return}case"get-source-file":{let i=await this.resolveWireContext(s);this.sendResult(o,s.kind,x(await this.options.engine.getSourceFile({path:s.path,composition:i}),i));return}case"resolve-source-location":{let i=await this.resolveWireContext(s),r=x(await this.options.engine.resolveSourceLocation({key:s.key,composition:i}),i);this.sendResult(o,s.kind,r);return}case"execute":{let i=await this.resolveOperationWireContext(s.request),r=await this.resolveWireContext(s);if(C(i)!==C(r))throw new v(yt,"The execute request composition does not match its operation composition.");let a=await this.normalizeOperationRequest(s.request,i);await this.handleBufferedOperation(o,s.kind,()=>this.options.engine.execute(a));return}case"undo":case"redo":{let i=await this.resolveWireContext(s);await this.handleBufferedOperation(o,s.kind,()=>s.kind==="undo"?this.options.engine.undo(i):this.options.engine.redo(i));return}}}catch(n){let s=m.extractRequestInfo(e);this.sendJson({type:"error",payload:{...s,message:G(n),code:J(n)}})}}async resolve(e){return this.options.engine.resolveComposition(e)}async resolveAndAssert(e){let n=await this.resolve(e),s=this.session.activeComposition;if(!s)throw new v(Z,"Initialize a composition session before issuing this request.");if(C(s)!==C(n.context))throw new v(yt,"The request composition does not match the active socket session.");return n.context}async resolveWireContext(e){let n=L(e);return this.resolveAndAssert(n)}async resolveOperationWireContext(e){let n=Gt(e);return this.resolveAndAssert(n)}activateSession(e){this.session.activeComposition=e,this.session.subscribedCompositionKeys.clear(),this.session.subscribedCompositionKeys.add(C(e))}async normalizeOperationRequest(e,n){let s={...e,composition:St(n)};if(s.target.kind==="route"){let o=s.target,i=L(o),r=await this.resolveAndAssert(i);s.target={...o,composition:St(r)}}return s}handleEngineEvent(e){let n=e?.composition;if(!Jt(n))return;let s=C(n);this.session.subscribedCompositionKeys.has(s)&&(this.eventDispatcher.push(e),e.type==="site-edit.graph.invalidated"&&s===Qt(this.session)&&(this.session.activeComposition=void 0,this.session.subscribedCompositionKeys.delete(s)))}sendResult(e,n,s){this.sendJson({type:"response",payload:{id:e,kind:n,result:s}})}async handleRawMessage(e){try{await this.handleMessage(m.parseMessage(e,{validateOperationRequest:this.options.validateOperationRequest}))}catch(n){let s=Zt(e);this.sendJson({type:"error",payload:{...s,message:G(n),code:J(n)}})}}sendJson(e){this.options.socket.send(m.stringifyMessage(e))}async handleBufferedOperation(e,n,s){this.eventDispatcher.beginBuffering();try{let o=await s();this.sendResult(e,n,o)}catch(o){this.sendJson({type:"error",payload:{id:e,kind:n,message:G(o),code:J(o)}})}finally{this.eventDispatcher.flush()}}},v=class extends Error{constructor(e,n){super(n),this.code=e,this.name="BridgeProtocolError"}},Q=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))}},Y=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()},s=this.queue.then(n,n);return this.queue=s.then(()=>{},()=>{}),s}};function Lt(t,e){if(!f(t)||typeof t.id!="string"||!m.isRequestKind(t.kind))return!1;let n=k(t.composition);switch(t.kind){case"initialize-session":return n&&(t.mutationContext===void 0||z(t.mutationContext));case"get-document":case"get-style-context":return n;case"get-object-edit-context":case"get-class-name-source":case"resolve-source-location":return typeof t.key=="string"&&n;case"get-history-status":return n;case"get-source-tree":return n;case"get-source-file":return typeof t.path=="string"&&n;case"execute":return n&&zt(t.request)&&(t.request.mutationContext===void 0||z(t.request.mutationContext))&&(e.validateOperationRequest?.(t.request)??!0);case"undo":case"redo":return n&&t.mutationContext===void 0||n&&z(t.mutationContext)}}function zt(t){return f(t)&&typeof t.id=="string"&&typeof t.siteId=="string"&&typeof t.baseSnapshotId=="string"&&k(t.composition)&&typeof t.kind=="string"&&f(t.target)&&(t.target.kind!=="route"||k(t.target.composition))&&typeof t.documentVersion=="number"&&Number.isInteger(t.documentVersion)&&t.documentVersion>=0&&f(t.params)}function k(t){return f(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 Jt(t){return f(t)&&typeof t.routeId=="string"&&(t.effectiveTemplateId===void 0||typeof t.effectiveTemplateId=="string")}function L(t){if(k(t.composition))return t.composition;throw new v(Z,"A composition selector is required for this request.")}function Gt(t){if(f(t)&&k(t.composition))return t.composition;throw new v(Z,"A composition selector is required for execute.")}function St(t){return{routeId:t.routeId,...t.effectiveTemplateId?{templateId:t.effectiveTemplateId}:{}}}function Qt(t){return t.activeComposition?C(t.activeComposition):null}function C(t){return JSON.stringify([t.routeId,t.effectiveTemplateId??null])}function x(t,e){return f(t)&&t.ok===!0?{...t,composition:e}:t}function Yt(t,e){return!f(t)||t.ok!==!0?t:{...t,...e?{composition:e}:{},data:It(t.data)}}function It(t){let e=t;return gt(e.routeId?e:{...e,routeId:e.composition.routeId})}function f(t){return typeof t=="object"&&t!==null}function z(t){return f(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 J(t){if(!(!f(t)||typeof t.code!="string"||t.code.length===0))return t.code}function G(t){return t instanceof Error||f(t)&&typeof t.message=="string"&&t.message.length>0?t.message:"Unknown websocket operation failure"}function Zt(t){try{return m.extractRequestInfo(JSON.parse(t))}catch{return{id:"unknown",kind:"get-document"}}}var F=class{constructor(){this.tail=Promise.resolve()}run(e){let n=this.tail.then(e,e);return this.tail=n.then(()=>{},()=>{}),n}};import{SiteEditOperationRequestSchema as de,computeSiteEditCompositionKey as R}from"@vcp-dev/contracts";var he="127.0.0.1",pe=30218,fe="/__vcp/site-edit/bridge",bt=6*1024*1024,le=bt*2,me=3e3,wt=50,et=".vcp/current-snapshot.json",xt="__VCP_SITE_EDIT_BRIDGE_SERVERS__";function _t(t,e,n={}){let s=new nt(ge(e),t,!1,n);return s.start({listen:!1}),s}var nt=class{constructor(e,n=Xt.createServer((i,r)=>{r.writeHead(404),r.end("VCP site edit bridge server")}),s=!0,o={}){this.options=e,this.server=n,this.closeHttpServerOnStop=s,this.dependencies=o,this.runtime=null,this.activeHistorySessionId=null,this.historySessionTransition=Promise.resolve(),this.mutationQueue=new F,this.eventListeners=new Set,this.routes=[],this.compositions=[],this.compositionFiles=[],this.compositionResolutionError=null,this.stopWatching=null,this.stopWebSocketServer=null,this.pendingChangedFiles=new Set,this.fileChangeTimer=null,this.isStarted=!1,this.stopping=!1,this.runtimeVersionFloors=new Map,this.activeHistoryStore=null,this.versionPersistence=Promise.resolve()}start(e={}){if(this.isStarted)return;this.stopping=!1;try{P.mkdirSync(g.join(this.options.projectRoot,".vcp"),{recursive:!0})}catch(s){console.warn(`[vcp-site-edit] failed to ensure .vcp directory: ${s instanceof Error?s.message:String(s)}`)}this.refreshCompositions(!0),this.isStarted=!0,this.createRuntime();let n=ve({server:this.server,path:this.options.path,sessionKey:this.options.sessionKey,host:this.options.host,allowedOrigins:this.options.allowedOrigins,engine:this.createBridgeEngine()});this.stopWebSocketServer=n.stop,this.stopWatching=new ue({projectRoot:this.options.projectRoot,watch_dirs:ye(this.options.runtime.watch_dirs),interval_ms:this.options.runtime.watch_interval_ms,debounce_ms:this.options.runtime.watch_debounce_ms??wt,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:s=>this.handleFileChanged(s),on_batch_change:s=>this.handleFilesChanged(s)}).start(),e.listen!==!1&&this.server.listen(this.options.port,this.options.host)}getHealth(){let e=!!this.runtime&&!this.compositionResolutionError;return{ok:this.isStarted&&e,bridgePath:this.options.path,runtimeReady:e,routesIndexed:this.routes.length,sessionRequired:!!this.options.sessionKey}}stop(){this.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=xe(),n=Ce(this.options);e.get(n)===this&&e.delete(n),this.isStarted=!1}createRuntime(e,n=null){let s=this.runtime;this.activeHistoryStore=e??null;let o=(this.dependencies.createRuntime??se)({...this.options.tenantId?{tenantId:this.options.tenantId}:{},siteId:this.options.siteId,snapshotId:this.options.snapshotId,projectRoot:this.options.projectRoot,compositions:this.compositions,onEvent:i=>{"version"in i&&typeof i.version=="number"&&this.recordRuntimeVersion(i.version,"composition"in i?i.composition:void 0);for(let r of this.eventListeners)r(i)},...e?{historyStore:e}:{},...this.getInitialDocumentVersions().length>0?{initialDocumentVersions:this.getInitialDocumentVersions()}:{}});this.runtime=o,this.activeHistorySessionId=n,s?.dispose()}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 s=Ie(e.composition),o=this.getRuntime(),i=y(s);await o.initializeComposition(i);let a=o.getDocument(i).data;await this.recordRuntimeVersion(a.version,s);let u=(await o.getHistoryStatus()).data;return{ok:!0,composition:s,data:{document:a,historyStatus:u}}}),getDocument:async e=>{let n=this.getRuntime(),s=y(e);await n.initializeComposition(s);let o=n.getDocument(s);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)=>this.getRuntime().getObjectEditContext(e,y(n)),getClassNameSource:async(e,n)=>this.getRuntime().getClassNameSource(e,y(n)),getSourceTree:async e=>this.getRuntime().getSourceTree(y(e)),getSourceFile:async e=>this.getRuntime().getSourceFile({path:e.path,composition:y(e.composition)}),resolveSourceLocation:async e=>this.getRuntime().resolveSourceLocation({key:e.key,composition:y(e.composition)}),execute:(e,n)=>this.mutationQueue.run(async()=>{let s=await this.bindHistorySession(this.options.snapshotId);if(!s.ok)return X(s,e);let o=await this.getRuntime().executeOperation(e);return o.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(o.data.resultVersion,o.composition),o}),undo:e=>this.mutationQueue.run(async()=>{let n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)return X(n,void 0,e);let s=await this.getRuntime().undo();return s.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(s.data.resultVersion,s.composition??e),s.composition?s:{...s,composition:e}}),redo:e=>this.mutationQueue.run(async()=>{let n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)return X(n,void 0,e);let s=await this.getRuntime().redo();return s.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(s.data.resultVersion,s.composition??e),s.composition?s:{...s,composition:e}}),subscribe:e=>(this.eventListeners.add(e),()=>this.eventListeners.delete(e))}}async bindHistorySession(e){if(!this.options.historyRoot)return{ok:!1,code:"RECOVERY_PERSIST_FAILED",message:"Durable edit history is not configured."};if(this.activeHistorySessionId===e)return{ok:!0};let n=this.historySessionTransition.then(async()=>{if(this.activeHistorySessionId===e)return;let s=await(this.dependencies.openHistoryStore??oe)(we({root:this.options.historyRoot,siteId:this.options.siteId,snapshotId:this.options.snapshotId,editingSessionId:e}));if(!this.isStarted)return;let o=s.readDocumentVersion?await s.readDocumentVersion():0,i=this.compositions[0]?.context;if(i){let r=R(i);this.runtimeVersionFloors.set(r,Math.max(this.runtimeVersionFloors.get(r)??0,o))}this.createRuntime(s,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 s=n?R(n):null;s&&this.runtimeVersionFloors.set(s,Math.max(this.runtimeVersionFloors.get(s)??0,e));let o=this.activeHistoryStore;if(!o?.writeDocumentVersion)return Promise.resolve();let i=s?this.runtimeVersionFloors.get(s)??e:e;return this.versionPersistence=this.versionPersistence.then(()=>o.writeDocumentVersion(i)).catch(()=>{}),this.versionPersistence}handleFileChanged(e){this.handleFilesChanged([e])}handleFilesChanged(e){for(let s of e)this.pendingChangedFiles.add(s);this.fileChangeTimer&&clearTimeout(this.fileChangeTimer);let n=this.options.runtime.watch_debounce_ms??wt;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,s)=>n.localeCompare(s));if(this.pendingChangedFiles.clear(),e.some(He)&&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=P.readFileSync(g.join(this.options.projectRoot,et),"utf8"),n=JSON.parse(e),s=typeof n.snapshot_id=="string"?n.snapshot_id:"";return!s||st(s)!==s?(console.warn("[vcp-site-edit] current-snapshot marker has no valid snapshot_id"),null):s}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 s=new Date().toISOString();for(let o of this.compositions){let i={type:"site-edit.snapshot.changed",siteId:this.options.siteId,composition:o.context,snapshotId:e,previousSnapshotId:n,at:s};for(let r of this.eventListeners)try{r(i)}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=Se(this.options.projectRoot),s=ce(n),o=s.length>0?s:(this.options.runtime.routes??[]).map(u=>({...u})),i=re({files:n});if(i.length===0)throw new Error("No canonical App Router composition is indexed by the preview bridge.");let r=new Map(this.compositions.map(u=>[R(u.context),u])),a=new Map(i.map(u=>[R(u.context),u]));if(this.runtime){for(let[u,c]of r){let h=a.get(u);(!h||h.entryFile!==c.entryFile)&&this.runtime.unregisterComposition(y(c.context))}for(let[u,c]of a){let h=r.get(u);(!h||h.entryFile!==c.entryFile)&&this.runtime.registerComposition(c.context,c.entryFile)}}return this.routes=o,this.compositions=i,this.compositionFiles=n,this.compositionResolutionError=null,!0}catch(n){let s=n instanceof Error?n:new Error(String(n));if(this.compositionResolutionError=s,e)throw s;return!1}}resolveComposition(e){if(this.compositionResolutionError)throw this.compositionResolutionError;let n=ae(e.routeId,this.routes,this.options.basePath);if(!n)throw new Error(`Route is not indexed by the preview bridge: ${e.routeId}`);let s=this.routes.find(r=>r.routeId===n);if(!s)throw new Error(`Route is not indexed by the preview bridge: ${e.routeId}`);let o=ie({selector:{routeId:n,...e.templateId?{templateId:e.templateId}:{}},files:this.compositionFiles,canonicalEntryFile:s.entryFile}),i=R(o.context);if(!this.compositions.some(r=>R(r.context)===i))throw new Error(`Composition is not registered by the preview bridge: ${i}`);return o}getInitialDocumentVersions(){return this.compositions.flatMap(e=>{let n=this.runtimeVersionFloors.get(R(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 ge(t){return{tenantId:t.tenantId,siteId:t.siteId,snapshotId:t.snapshotId,projectRoot:g.resolve(t.projectRoot??process.cwd()),basePath:t.basePath??"",host:t.host??he,port:t.port??pe,path:t.path??fe,sessionKey:t.sessionKey??Pe(),historyRoot:t.historyRoot,allowedOrigins:t.allowedOrigins??[],runtime:t.runtime??{},onSnapshotIdChanged:t.onSnapshotIdChanged}}function ye(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 Se(t){let e=[],n=["app","src/app",".vcp"],s=new Set([".git",".next",".turbo","coverage","dist","node_modules","output","snapshot-store"]),o=i=>{if(!P.existsSync(i))return;let r;try{r=P.readdirSync(i,{withFileTypes:!0})}catch{return}for(let a of r){if(a.name.startsWith(".")&&a.name!==".vcp")continue;if(a.isDirectory()){if(s.has(a.name))continue;o(g.join(i,a.name));continue}if(!a.isFile())continue;let u=g.join(i,a.name),c="";try{c=P.readFileSync(u,"utf8")}catch{}e.push({path:g.relative(t,u).replaceAll(g.sep,"/"),content:c})}};for(let i of n)o(g.join(t,i));return e.sort((i,r)=>i.path.localeCompare(r.path))}function Ie(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 we(t){return g.join(g.resolve(t.root),st(t.siteId),st(t.snapshotId),Rt("sha256").update(t.editingSessionId).digest("hex").slice(0,32))}function st(t){return/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(t)&&t!=="."&&t!==".."?t:Rt("sha256").update(t).digest("hex").slice(0,32)}function xe(){let t=globalThis;return t[xt]??=new Map,t[xt]}function Ce(t){return`${t.projectRoot}:${t.host}:${t.port}:${t.path}:${t.historyRoot??""}`}function X(t,e,n){let s=n??(e?.composition?{routeId:e.composition.routeId,...e.composition.templateId?{effectiveTemplateId:e.composition.templateId}:{}}:void 0);if(!s)throw new Error("A normalized composition is required to construct a mutation result.");return{ok:!1,composition:s,error:{code:t.code,message:t.message},data:{requestId:e?.id??"mutation-context",kind:e?.kind??"update-text",composition:s,target:e?.target??{kind:"node",key:""},resultVersion:e?.documentVersion??0}}}function ve(t){let e=new ne({maxPayload:bt,noServer:!0}),n=new WeakSet,s=i=>{new j({socket:new ot(i),engine:t.engine,validateOperationRequest:r=>de.safeParse(r).success})},o=(i,r,a)=>{if(!Re(i,t))return;let u=Ee(i,t);if(!u){r.write(`HTTP/1.1 401 Unauthorized\r
2
2
  Connection: close\r
3
3
  \r
4
- `),r.destroy();return}c.authenticatedByHeader&&n.add(o),t.handleUpgrade(o,r,u,a=>{t.emit("connection",a,o)})};return e.server.on("upgrade",s),t.on("connection",(o,r)=>{if(n.has(r)){i(o);return}Et(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 ne=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===Re.OPEN){if(this.socket.bufferedAmount+Buffer.byteLength(t,"utf8")>ft){this.socket.close(1013,"bridge backpressure");return}this.socket.send(t)}}close(t,n){this.socket.close(t,n)}};function Rt(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=ee(e.headers["x-vcp-site-edit-key"]),s=ve(i,t.sessionKey),o=ee(e.headers.host),r=ee(e.headers.origin);return o&&!vt(o,t.host,r)?null:r?Tt(r,o,t.allowedOrigins)?{authenticatedByHeader:s}:null:s?{authenticatedByHeader:!0}:null}function Et(e,t,n){let i=setTimeout(()=>{e.close(1008,"bridge authentication timeout")},lt),s,o=()=>{clearTimeout(i),e.off("message",s),e.off("close",o)},r=()=>{o(),e.close(1008,"bridge authentication failed")};s=u=>{try{let c=m.parseMessage(u.toString());if(c.type!=="auth"||!ve(c.payload.key,t)){r();return}o(),e.readyState===Re.OPEN&&e.send(m.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&&et(n,i)}function vt(e,t,n){let i=xe(e),s=xe(t);return i===s||we(s)&&we(i)&&(!n||ie(n,e))||_t(s)&&(!n||ie(n,e))}function _t(e){return e==="0.0.0.0"||e==="::"}function we(e){return e==="localhost"||e==="127.0.0.1"||e==="::1"}function Tt(e,t,n){return n.includes(e)||(t?ie(e,t):!1)}function ie(e,t){try{return new URL(e).host===_e(t)}catch{return!1}}function xe(e){let t=_e(e);return t.startsWith("[")?t.slice(1,t.indexOf("]")):t.split(":").length-1===1?t.split(":",1)[0]??"":t}function _e(e){return e.trim().toLowerCase()}function ee(e){return Array.isArray(e)?e[0]:e}function kt(){return Xe(32).toString("base64url")}var Ht="next",De="127.0.0.1",Bt=3e3,U="/__vcp/site-edit/bridge",Oe="/__vcp/site-edit/health",At="probe",Dt="render",ke="/_error",K="/__vcp/site-edit/client/",Ot=`${K}auto-bootstrap.js`,Me='data-vcp-site-edit-bootstrap="true"',Mt=["next.config.ts","next.config.mts","next.config.cts","next.config.js","next.config.mjs","next.config.cjs"],Nt="@vcp-dev/site-edit-engine/webpack-loader",jt=/@vcp\/site-edit-engine\/(?:webpack-loader|site-edit-instrumentation-loader)/,Ft=[/\bconfig\.webpack\s*=/,/\bwebpack\s*\([^)]*\)\s*\{/,/\bwebpack\s*:\s*(?:async\s*)?(?:\([^)]*\)|[A-Za-z_$][\w$]*)?\s*=>/,/\bwebpack\s*:\s*(?:async\s+)?function\b/],Ut=new Set(["auto-bootstrap.js","client.js","composition-key.js","designer-trace.js","document-codec.js","protocol.js","window-message.js"]);async function Yn(e={},t={}){let n=t.process??process,i=t.createServer??ae.createServer,s=t.attachBridgeServer??Ee,o=t.loadNext??yn,r=k.resolve(e.projectRoot??process.cwd()),u=e.host??De,c=e.port??xn(n.env.PORT)??Bt,a=e.bridgePath??U,h=zt(a),d=pn(),p=e.basePath??n.env.VCP_SITE_PREVIEW_BASE_PATH??"/",l=(e.tenantId??n.env.VCP_TENANT_ID)?.trim()||void 0,y=await o(r),S=Kt(r),I=y({dev:!0,dir:r,hostname:u,port:c,...Vt(S)}),Fe=I.getRequestHandler(),Ue=e.siteId??n.env.VCP_SITE_ID??"018f6f4d-a9b8-7120-8000-000000000120",ue=e.snapshotId??n.env.VCP_SNAPSHOT_ID??wn(r),de=e.historyRoot??n.env.VCP_SITE_EDIT_HISTORY_ROOT,he=de?.trim()?k.resolve(de):void 0,B=null,Ke={launchId:Pt(),pid:process.pid,snapshotId:ue},E=i((W,O)=>{en({basePath:p,bridgePath:a,bridgeHealthPath:h,bridgeSessionKey:d,getBridgeHealth:()=>B?.getHealth()??rn(a),launch:Ke,runRenderProbe:()=>nn(I),handle:Fe,request:W,response:O}).catch(Ve=>{console.error(Ve),O.headersSent||(O.statusCode=500),O.end("site edit preview request failed")})}),V=null,A=null,q=()=>A||(F(()=>n.off("SIGINT",D)),F(()=>n.off("SIGTERM",D)),F(()=>V?.()),V=null,F(()=>B?.stop()),B=null,A=Promise.allSettled([Rn(E),bn(()=>I.close())]).then(()=>{}),A),D=()=>{q()};try{return await I.prepare(),B=s(E,{...l?{tenantId:l}:{},siteId:Ue,snapshotId:ue,projectRoot:r,basePath:p,host:u,port:c,path:a,sessionKey:d,...he?{historyRoot:he}:{}}),V=Lt({server:E,bridgePath:a,handleUpgrade:I.getUpgradeHandler()}),n.on("SIGINT",D),n.on("SIGTERM",D),await Cn(E,c,u),{bundler:S,close:q,host:u,port:En(E,c),server:E}}catch(W){throw await q(),W}}function Kt(e){let t=qt(e);return t&&Wt(t)?"webpack":"turbopack"}function Vt(e){return e==="webpack"?{webpack:!0}:{turbopack:!0}}function qt(e){for(let t of Mt){let n=H(e,t);if(_(n))return v(n,"utf8")}return null}function Wt(e){return e.includes(Nt)?!0:jt.test(e)&&Ft.some(t=>t.test(e))}function Lt(e){let t=(n,i,s)=>{$t(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 $t(e,t){return new URL(e??"/","http://localhost").pathname===t}function zt(e=U){if(e===U)return Oe;let t=(e.startsWith("/")?e:`/${e}`).replace(/\/+$/,"");return t.endsWith("/bridge")?`${t.slice(0,-7)}/health`:t?`${t}/health`:"/health"}function Jt(e){let t=JSON.stringify({basePath:e.basePath,wsPath:e.bridgePath,bridge_session_key:e.bridgeSessionKey,defer_initial_sync:!0,runtime_versions:e.runtimeVersions??Gt()});return`<script type="module" ${Me}>import { startSiteEditAutoBootstrap } from ${JSON.stringify(Ot)};void startSiteEditAutoBootstrap(window, ${t}).catch(() => undefined);</script>`}function Gt(){return{bridge:oe("@vcp-dev/site-edit-bridge"),contracts:oe("@vcp-dev/contracts"),engine:oe("@vcp-dev/site-edit-engine")}}function oe(e){let t=He(import.meta.url);try{let n=t.resolve(e),i=Qt(n,e);if(!i)return;let s=JSON.parse(v(i,"utf8"));return typeof s.version=="string"?s.version:void 0}catch{return}}function Qt(e,t){let n=k.parse(e).root,i=P(e);for(;i&&i!==n;){let s=H(i,"package.json");if(_(s))try{if(JSON.parse(v(s,"utf8")).name===t)return s}catch{return}i=P(i)}}function Yt(e,t){if(e.includes(Me))return e;let n=Jt(t),i=/<\/body\s*>/i.exec(e);return i?`${e.slice(0,i.index)}${n}${e.slice(i.index)}`:`${e}${n}`}function Zn(e,t=P(Ae(import.meta.url)),n=_){return Ne(e,t,n)?.path??null}function Ne(e,t=P(Ae(import.meta.url)),n=_){let i=new URL(e??"/","http://localhost").pathname;if(!i.startsWith(K))return null;let s=i.slice(K.length);if(!Ut.has(s))return null;let o=ce(Sn(t),s);if(Be(t)!=="src")return{path:o,requiresTranspile:!1};let r=ce(t,s.replace(/\.js$/,".ts"));return n(r)?{path:r,requiresTranspile:!0}:{path:o,requiresTranspile:!1}}async function Zt(e,t){let n=Ne(e.url);if(!n)return!1;if(!_(n.path))return t.writeHead(404),t.end("site edit client asset not found"),!0;let i=n.requiresTranspile?await Xt(v(n.path,"utf8")):v(n.path);return t.writeHead(200,{"cache-control":"no-store","content-type":"text/javascript; charset=utf-8"}),t.end(i),!0}async function Xt(e){let t=await import("typescript");return t.transpileModule(e,{compilerOptions:{module:t.ModuleKind.ES2022,target:t.ScriptTarget.ES2022}}).outputText}async function en({basePath:e,bridgePath:t,bridgeHealthPath:n,bridgeSessionKey:i,getBridgeHealth:s,launch:o,runRenderProbe:r,handle:u,request:c,response:a}){if(await sn(c,a,n,s,o,r)||await Zt(c,a))return;let h=an(c),d=cn(c),p=h||d?hn(a,{basePath:e,bridgePath:t,bridgeSessionKey:i,patchNextDevChunk:d}):()=>{};try{await u(c,a)}catch(l){throw p(),l}}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 nn(e){let t=new ae.IncomingMessage(new Te);t.method="GET",t.url=ke,t.headers={host:De};let n=new ae.ServerResponse(t);n.assignSocket(new Te);try{return await e.renderToHTML(t,n,ke,{}),{verdict:"ok"}}catch(i){return tn(i)}finally{try{let i=n.socket;i&&(n.detachSocket(i),i.destroy())}catch{}}}function on(e){return new URL(e??"/","http://localhost").searchParams.get(At)===Dt}async function sn(e,t,n,i,s,o){if(e.method!=="GET"||new URL(e.url??"/","http://localhost").pathname!==n)return!1;let u=i(),c=on(e.url)?await o():void 0,a={...u,launch:s,...c?{render:c}:{}};return t.writeHead(u.ok?200:503,{"cache-control":"no-store","content-type":"application/json; charset=utf-8"}),t.end(JSON.stringify(a)),!0}function rn(e){return{ok:!1,bridgePath:e,runtimeReady:!1,routesIndexed:0,sessionRequired:!0}}function an(e){return un(e)?(e.headers["accept-encoding"]="identity",!0):!1}function cn(e){return dn(e)?(e.headers["accept-encoding"]="identity",!0):!1}function un(e){if(e.method!=="GET")return!1;let t=new URL(e.url??"/","http://localhost").pathname;if(t.startsWith("/_next/")||t.startsWith(K)||t===U||t===Oe)return!1;let n=e.headers.accept??"";return n===""||n.includes("text/html")}function dn(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 hn(e,t){let n=[],i=e,s=i.flushHeaders.bind(e),o=i.write.bind(e),r=i.end.bind(e),u=!1;i.flushHeaders=()=>{};let c=()=>{if(t.patchNextDevChunk||u)return!1;let a=Buffer.concat(n);if(!/<body\b[^>]*>/iu.test(a.toString("utf8")))return!1;let h=Pe(e,a,t);return h!==a&&!e.headersSent&&e.removeHeader("content-length"),o(h),n.length=0,u=!0,!0};return i.write=(a,h,d)=>u?(a!==void 0&&o(se(a,re(h))),j(h),j(d),!0):(a!==void 0&&(n.push(se(a,re(h))),c()),j(h),j(d),!0),i.end=(a,h,d)=>{let p=typeof a=="function"?void 0:a;if(u)return i.write=o,i.end=r,i.flushHeaders=s,p===void 0?typeof a=="function"?r(a):typeof h=="function"?r(h):typeof d=="function"?r(d):r():typeof h=="function"?r(p,h):typeof d=="function"?r(p,h,d):r(p,h);p!==void 0&&n.push(se(p,re(h))),i.write=o,i.end=r,i.flushHeaders=s;let l=Buffer.concat(n),y=Pe(e,l,t);y!==l&&!e.headersSent&&e.removeHeader("content-length");let S=typeof a=="function"?a:typeof h=="function"?h:typeof d=="function"?d:void 0;return S?r(y,S):r(y)},()=>{i.write=o,i.end=r,i.flushHeaders=s}}function Pe(e,t,n){if(fn(e,t))return Buffer.from(Yt(t.toString("utf8"),n));if(n.patchNextDevChunk&&ln(e)){let i=t.toString("utf8"),s=mn(i);if(s!==i)return Buffer.from(s)}return t}function pn(){let e=new Uint8Array(32);return globalThis.crypto.getRandomValues(e),Buffer.from(e).toString("base64url")}function fn(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 ln(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 mn(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}u.authenticatedByHeader&&n.add(i),e.handleUpgrade(i,r,a,c=>{e.emit("connection",c,i)})};return t.server.on("upgrade",o),e.on("connection",(i,r)=>{if(n.has(r)){s(i);return}be(i,t.sessionKey,()=>{s(i)})}),e.stop=()=>{t.server.off("upgrade",o);for(let i of e.clients)i.close(1001,"bridge stopped");e.close()},e}var ot=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===Et.OPEN){if(this.socket.bufferedAmount+Buffer.byteLength(e,"utf8")>le){this.socket.close(1013,"bridge backpressure");return}this.socket.send(e)}}close(e,n){this.socket.close(e,n)}};function Re(t,e){return new URL(t.url??"/","http://localhost").pathname===e.path}function Ee(t,e){if(new URL(t.url??"/","http://localhost").searchParams.has("vcp_bridge_key"))return null;let s=tt(t.headers["x-vcp-site-edit-key"]),o=Tt(s,e.sessionKey),i=tt(t.headers.host),r=tt(t.headers.origin);return i&&!_e(i,e.host,r)?null:r?ke(r,i,e.allowedOrigins)?{authenticatedByHeader:o}:null:o?{authenticatedByHeader:!0}:null}function be(t,e,n){let s=setTimeout(()=>{t.close(1008,"bridge authentication timeout")},me),o,i=()=>{clearTimeout(s),t.off("message",o),t.off("close",i)},r=()=>{i(),t.close(1008,"bridge authentication failed")};o=a=>{try{let u=m.parseMessage(a.toString());if(u.type!=="auth"||!Tt(u.payload.key,e)){r();return}i(),t.readyState===Et.OPEN&&t.send(m.stringifyMessage({type:"auth-ok",payload:{ok:!0}})),n()}catch{r()}},t.on("message",o),t.on("close",i)}function Tt(t,e){if(!t)return!1;let n=Buffer.from(t),s=Buffer.from(e);return n.length===s.length&&ee(n,s)}function _e(t,e,n){let s=vt(t),o=vt(e);return s===o||Ct(o)&&Ct(s)&&(!n||it(n,t))||Te(o)&&(!n||it(n,t))}function Te(t){return t==="0.0.0.0"||t==="::"}function Ct(t){return t==="localhost"||t==="127.0.0.1"||t==="::1"}function ke(t,e,n){return n.includes(t)||(e?it(t,e):!1)}function it(t,e){try{return new URL(t).host===kt(e)}catch{return!1}}function vt(t){let e=kt(t);return e.startsWith("[")?e.slice(1,e.indexOf("]")):e.split(":").length-1===1?e.split(":",1)[0]??"":e}function kt(t){return t.trim().toLowerCase()}function tt(t){return Array.isArray(t)?t[0]:t}function Pe(){return te(32).toString("base64url")}function He(t){let e=t.replaceAll("\\","/");return e===et||e.endsWith(`/${et}`)}var Be="next",Mt="127.0.0.1",De=3e3,V="/__vcp/site-edit/bridge",Nt="/__vcp/site-edit/health",Oe="probe",Me="render",Ht="/_error",q="/__vcp/site-edit/client/",Ne=`${q}auto-bootstrap.js`,jt='data-vcp-site-edit-bootstrap="true"',je=["next.config.ts","next.config.mts","next.config.cts","next.config.js","next.config.mjs","next.config.cjs"],Fe="@vcp-dev/site-edit-engine/webpack-loader",Ue=/@vcp\/site-edit-engine\/(?:webpack-loader|site-edit-instrumentation-loader)/,Ke=[/\bconfig\.webpack\s*=/,/\bwebpack\s*\([^)]*\)\s*\{/,/\bwebpack\s*:\s*(?:async\s*)?(?:\([^)]*\)|[A-Za-z_$][\w$]*)?\s*=>/,/\bwebpack\s*:\s*(?:async\s+)?function\b/],Ve=new Set(["auto-bootstrap.js","client.js","composition-key.js","designer-trace.js","document-codec.js","protocol.js","window-message.js"]);async function Xn(t={},e={}){let n=e.process??process,s=e.createServer??ut.createServer,o=e.attachBridgeServer??_t,i=e.loadNext??In,r=H.resolve(t.projectRoot??process.cwd()),a=t.host??Mt,u=t.port??vn(n.env.PORT)??De,c=t.bridgePath??V,h=Ge(c),d=ln(),p=t.basePath??n.env.VCP_SITE_PREVIEW_BASE_PATH??"/",l=(t.tenantId??n.env.VCP_TENANT_ID)?.trim()||void 0,S=await i(r),I=qe(r),w=S({dev:!0,dir:r,hostname:a,port:u,...$e(I)}),Kt=w.getRequestHandler(),Vt=t.siteId??n.env.VCP_SITE_ID??"018f6f4d-a9b8-7120-8000-000000000120",ht=t.snapshotId??n.env.VCP_SNAPSHOT_ID??Cn(r),pt=t.historyRoot??n.env.VCP_SITE_EDIT_HISTORY_ROOT,ft=pt?.trim()?H.resolve(pt):void 0,D=null,lt={launchId:Ae(),pid:process.pid,snapshotId:ht},E=s((T,N)=>{nn({basePath:p,bridgePath:c,bridgeHealthPath:h,bridgeSessionKey:d,getBridgeHealth:()=>D?.getHealth()??cn(c),launch:lt,runRenderProbe:()=>on(w),handle:Kt,request:T,response:N}).catch(qt=>{console.error(qt),N.headersSent||(N.statusCode=500),N.end("site edit preview request failed")})}),$=null,O=null,W=()=>O||(K(()=>n.off("SIGINT",M)),K(()=>n.off("SIGTERM",M)),K(()=>$?.()),$=null,K(()=>D?.stop()),D=null,O=Promise.allSettled([En(E),bn(()=>w.close())]).then(()=>{}),O),M=()=>{W()};try{return await w.prepare(),D=o(E,{...l?{tenantId:l}:{},siteId:Vt,snapshotId:ht,projectRoot:r,basePath:p,host:a,port:u,path:c,sessionKey:d,...ft?{historyRoot:ft}:{},onSnapshotIdChanged:T=>{lt.snapshotId=T}}),$=ze({server:E,bridgePath:c,handleUpgrade:w.getUpgradeHandler()}),n.on("SIGINT",M),n.on("SIGTERM",M),await Rn(E,u,a),{bundler:I,close:W,host:a,port:_n(E,u),server:E}}catch(T){throw await W(),T}}function qe(t){let e=We(t);return e&&Le(e)?"webpack":"turbopack"}function $e(t){return t==="webpack"?{webpack:!0}:{turbopack:!0}}function We(t){for(let e of je){let n=B(t,e);if(_(n))return b(n,"utf8")}return null}function Le(t){return t.includes(Fe)?!0:Ue.test(t)&&Ke.some(e=>e.test(t))}function ze(t){let e=(n,s,o)=>{Je(n.url,t.bridgePath)||t.handleUpgrade(n,s,o).catch(i=>{console.error(i),s.destroyed||s.destroy()})};return t.server.on("upgrade",e),()=>t.server.off("upgrade",e)}function Je(t,e){return new URL(t??"/","http://localhost").pathname===e}function Ge(t=V){if(t===V)return Nt;let e=(t.startsWith("/")?t:`/${t}`).replace(/\/+$/,"");return e.endsWith("/bridge")?`${e.slice(0,-7)}/health`:e?`${e}/health`:"/health"}function Qe(t){let e=JSON.stringify({basePath:t.basePath,wsPath:t.bridgePath,bridge_session_key:t.bridgeSessionKey,defer_initial_sync:!0,runtime_versions:t.runtimeVersions??Ye()});return`<script type="module" ${jt}>import { startSiteEditAutoBootstrap } from ${JSON.stringify(Ne)};void startSiteEditAutoBootstrap(window, ${e}).catch(() => undefined);</script>`}function Ye(){return{bridge:rt("@vcp-dev/site-edit-bridge"),contracts:rt("@vcp-dev/contracts"),engine:rt("@vcp-dev/site-edit-engine")}}function rt(t){let e=Bt(import.meta.url);try{let n=e.resolve(t),s=Ze(n,t);if(!s)return;let o=JSON.parse(b(s,"utf8"));return typeof o.version=="string"?o.version:void 0}catch{return}}function Ze(t,e){let n=H.parse(t).root,s=A(t);for(;s&&s!==n;){let o=B(s,"package.json");if(_(o))try{if(JSON.parse(b(o,"utf8")).name===e)return o}catch{return}s=A(s)}}function Xe(t,e){if(t.includes(jt))return t;let n=Qe(e),s=/<\/body\s*>/i.exec(t);return s?`${t.slice(0,s.index)}${n}${t.slice(s.index)}`:`${t}${n}`}function ts(t,e=A(Ot(import.meta.url)),n=_){return Ft(t,e,n)?.path??null}function Ft(t,e=A(Ot(import.meta.url)),n=_){let s=new URL(t??"/","http://localhost").pathname;if(!s.startsWith(q))return null;let o=s.slice(q.length);if(!Ve.has(o))return null;let i=dt(wn(e),o);if(Dt(e)!=="src")return{path:i,requiresTranspile:!1};let r=dt(e,o.replace(/\.js$/,".ts"));return n(r)?{path:r,requiresTranspile:!0}:{path:i,requiresTranspile:!1}}async function tn(t,e){let n=Ft(t.url);if(!n)return!1;if(!_(n.path))return e.writeHead(404),e.end("site edit client asset not found"),!0;let s=n.requiresTranspile?await en(b(n.path,"utf8")):b(n.path);return e.writeHead(200,{"cache-control":"no-store","content-type":"text/javascript; charset=utf-8"}),e.end(s),!0}async function en(t){let e=await import("typescript");return e.transpileModule(t,{compilerOptions:{module:e.ModuleKind.ES2022,target:e.ScriptTarget.ES2022}}).outputText}async function nn({basePath:t,bridgePath:e,bridgeHealthPath:n,bridgeSessionKey:s,getBridgeHealth:o,launch:i,runRenderProbe:r,handle:a,request:u,response:c}){if(await an(u,c,n,o,i,r)||await tn(u,c))return;let h=un(u),d=dn(u),p=h||d?fn(c,{basePath:t,bridgePath:e,bridgeSessionKey:s,patchNextDevChunk:d}):()=>{};try{await a(u,c)}catch(l){throw p(),l}}function sn(t){let e=t instanceof Error?t.message:String(t),n=t&&typeof t=="object"&&"code"in t?t.code:void 0;return/\.next[/\\]/.test(e)||/chunks[/\\]ssr[/\\]/.test(e)?n==="ENOENT"||n==="MODULE_NOT_FOUND"?{verdict:"artifact_broken",detail:e}:e.includes("Cannot find module")?{verdict:"artifact_broken",detail:e}:{verdict:"inconclusive",detail:e}:{verdict:"inconclusive",detail:e}}async function on(t){let e=new ut.IncomingMessage(new Pt);e.method="GET",e.url=Ht,e.headers={host:Mt};let n=new ut.ServerResponse(e);n.assignSocket(new Pt);try{return await t.renderToHTML(e,n,Ht,{}),{verdict:"ok"}}catch(s){return sn(s)}finally{try{let s=n.socket;s&&(n.detachSocket(s),s.destroy())}catch{}}}function rn(t){return new URL(t??"/","http://localhost").searchParams.get(Oe)===Me}async function an(t,e,n,s,o,i){if(t.method!=="GET"||new URL(t.url??"/","http://localhost").pathname!==n)return!1;let a=s(),u=rn(t.url)?await i():void 0,c={...a,launch:o,...u?{render:u}:{}};return e.writeHead(a.ok?200:503,{"cache-control":"no-store","content-type":"application/json; charset=utf-8"}),e.end(JSON.stringify(c)),!0}function cn(t){return{ok:!1,bridgePath:t,runtimeReady:!1,routesIndexed:0,sessionRequired:!0}}function un(t){return hn(t)?(t.headers["accept-encoding"]="identity",!0):!1}function dn(t){return pn(t)?(t.headers["accept-encoding"]="identity",!0):!1}function hn(t){if(t.method!=="GET")return!1;let e=new URL(t.url??"/","http://localhost").pathname;if(e.startsWith("/_next/")||e.startsWith(q)||e===V||e===Nt)return!1;let n=t.headers.accept??"";return n===""||n.includes("text/html")}function pn(t){if(t.method!=="GET"||!String(t.headers["user-agent"]??"").includes("Firefox"))return!1;let n=new URL(t.url??"/","http://localhost").pathname;return n.startsWith("/_next/static/chunks/")&&n.endsWith(".js")}function fn(t,e){let n=[],s=t,o=s.flushHeaders.bind(t),i=s.write.bind(t),r=s.end.bind(t),a=!1;s.flushHeaders=()=>{};let u=()=>{if(e.patchNextDevChunk||a)return!1;let c=Buffer.concat(n);if(!/<body\b[^>]*>/iu.test(c.toString("utf8")))return!1;let h=At(t,c,e);return h!==c&&!t.headersSent&&t.removeHeader("content-length"),i(h),n.length=0,a=!0,!0};return s.write=(c,h,d)=>a?(c!==void 0&&i(at(c,ct(h))),U(h),U(d),!0):(c!==void 0&&(n.push(at(c,ct(h))),u()),U(h),U(d),!0),s.end=(c,h,d)=>{let p=typeof c=="function"?void 0:c;if(a)return s.write=i,s.end=r,s.flushHeaders=o,p===void 0?typeof c=="function"?r(c):typeof h=="function"?r(h):typeof d=="function"?r(d):r():typeof h=="function"?r(p,h):typeof d=="function"?r(p,h,d):r(p,h);p!==void 0&&n.push(at(p,ct(h))),s.write=i,s.end=r,s.flushHeaders=o;let l=Buffer.concat(n),S=At(t,l,e);S!==l&&!t.headersSent&&t.removeHeader("content-length");let I=typeof c=="function"?c:typeof h=="function"?h:typeof d=="function"?d:void 0;return I?r(S,I):r(S)},()=>{s.write=i,s.end=r,s.flushHeaders=o}}function At(t,e,n){if(mn(t,e))return Buffer.from(Xe(e.toString("utf8"),n));if(n.patchNextDevChunk&&gn(t)){let s=e.toString("utf8"),o=yn(s);if(o!==s)return Buffer.from(o)}return e}function ln(){let t=new Uint8Array(32);return globalThis.crypto.getRandomValues(t),Buffer.from(t).toString("base64url")}function mn(t,e){if(t.statusCode<200||t.statusCode>=300)return!1;let n=t.getHeader("content-type"),s=Array.isArray(n)?n.join(";"):String(n??"");return e.toString("utf8",0,256).includes("<html")&&(s===""||s.includes("text/html"))}function gn(t){if(t.statusCode<200||t.statusCode>=300)return!1;let e=t.getHeader("content-type"),n=Array.isArray(e)?e.join(";"):String(e??"");return n===""||n.includes("javascript")||n.includes("ecmascript")}function yn(t){return[["debugChannel = createDebugChannel(undefined);","debugChannel = undefined;"],["if (isStreamErrorOrUnfinished(ctr)) {","if (false) {"],["return ctr.desiredSize === null || ctr.desiredSize < 0;","return false;"],[["findSourceMapURL: _appfindsourcemapurl.findSourceMapURL,"," debugChannel,"," startTime: 0"].join(`
5
5
  `),["unstable_allowPartialStream: true,"," debugChannel,"," startTime: 0"].join(`
6
- `)],[["findSourceMapURL: _appfindsourcemapurl.findSourceMapURL,"," debugChannel,"," startTime: 0"].join("\\n"),["unstable_allowPartialStream: true,"," debugChannel,"," startTime: 0"].join("\\n")],["debugChannel: createDebugChannel && createDebugChannel(requestHeaders)","debugChannel: undefined"],["debugChannel: createDebugChannel && createDebugChannel(headers)","debugChannel: undefined"]].reduce((n,[i,s])=>gn(n,i,s),e)}function gn(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 se(e,t){return Buffer.isBuffer(e)?e:e instanceof Uint8Array?Buffer.from(e):Buffer.from(String(e),t)}function re(e){return typeof e=="string"?e:void 0}function j(e){typeof e=="function"&&e()}async function yn(e){let n=He(H(e,"package.json"))(Ht);return n.default??n}function Sn(e){return Be(e)!=="src"?e:ce(In(e),"dist")}function In(e){return je(e)?k.posix.dirname(e):P(e)}function ce(e,t){return je(e)?k.posix.join(e,t):H(e,t)}function je(e){return e.includes("/")&&!e.includes("\\")}function wn(e){let t=H(e,".vcp/current-snapshot.json");if(!_(t))return"sandbox_worktree";try{let n=JSON.parse(v(t,"utf8"));return typeof n.snapshotId=="string"?n.snapshotId:"sandbox_worktree"}catch{return"sandbox_worktree"}}function xn(e){if(!e)return null;let t=Number.parseInt(e,10);return Number.isInteger(t)&&t>0&&t<=65535?t:null}function Cn(e,t,n){return new Promise((i,s)=>{e.once("error",s),e.listen(t,n,()=>{e.off("error",s),i()})})}function Rn(e){return new Promise(t=>{e.close(()=>t())})}function F(e){try{e()}catch{}}function bn(e){try{return e()}catch(t){return Promise.reject(t)}}function En(e,t){let n=e.address();return typeof n=="object"&&n?n.port:t}export{Lt as attachNextDevUpgradeHandler,tn as classifySiteEditRenderProbeError,Jt as createSiteEditAutoBootstrapHtmlSnippet,Yt as injectSiteEditAutoBootstrap,on as isSiteEditRenderProbeRequested,mn as patchNextFirefoxDevChunk,cn as prepareFirefoxNextDevChunkPatchRequest,an as prepareSiteEditHtmlInjectionRequest,zt as resolveSiteEditBridgeHealthPath,Ne as resolveSiteEditClientAsset,Zn as resolveSiteEditClientAssetPath,Kt as resolveSiteEditNextDevBundler,nn as runSiteEditRenderProbe,Yn as startSiteEditNextDevServer,Xt as transpileSiteEditClientSource};
6
+ `)],[["findSourceMapURL: _appfindsourcemapurl.findSourceMapURL,"," debugChannel,"," startTime: 0"].join("\\n"),["unstable_allowPartialStream: true,"," debugChannel,"," startTime: 0"].join("\\n")],["debugChannel: createDebugChannel && createDebugChannel(requestHeaders)","debugChannel: undefined"],["debugChannel: createDebugChannel && createDebugChannel(headers)","debugChannel: undefined"]].reduce((n,[s,o])=>Sn(n,s,o),t)}function Sn(t,e,n){if(n.length>e.length)throw new Error("Replacement must not be longer than the search string.");return t.replaceAll(e,n.padEnd(e.length," "))}function at(t,e){return Buffer.isBuffer(t)?t:t instanceof Uint8Array?Buffer.from(t):Buffer.from(String(t),e)}function ct(t){return typeof t=="string"?t:void 0}function U(t){typeof t=="function"&&t()}async function In(t){let n=Bt(B(t,"package.json"))(Be);return n.default??n}function wn(t){return Dt(t)!=="src"?t:dt(xn(t),"dist")}function xn(t){return Ut(t)?H.posix.dirname(t):A(t)}function dt(t,e){return Ut(t)?H.posix.join(t,e):B(t,e)}function Ut(t){return t.includes("/")&&!t.includes("\\")}function Cn(t){let e=B(t,".vcp/current-snapshot.json");if(!_(e))return"sandbox_worktree";try{let n=JSON.parse(b(e,"utf8"));return typeof n.snapshot_id=="string"&&n.snapshot_id?n.snapshot_id:typeof n.snapshotId=="string"&&n.snapshotId?n.snapshotId:"sandbox_worktree"}catch{return"sandbox_worktree"}}function vn(t){if(!t)return null;let e=Number.parseInt(t,10);return Number.isInteger(e)&&e>0&&e<=65535?e:null}function Rn(t,e,n){return new Promise((s,o)=>{t.once("error",o),t.listen(e,n,()=>{t.off("error",o),s()})})}function En(t){return new Promise(e=>{t.close(()=>e())})}function K(t){try{t()}catch{}}function bn(t){try{return t()}catch(e){return Promise.reject(e)}}function _n(t,e){let n=t.address();return typeof n=="object"&&n?n.port:e}export{ze as attachNextDevUpgradeHandler,sn as classifySiteEditRenderProbeError,Qe as createSiteEditAutoBootstrapHtmlSnippet,Xe as injectSiteEditAutoBootstrap,rn as isSiteEditRenderProbeRequested,yn as patchNextFirefoxDevChunk,dn as prepareFirefoxNextDevChunkPatchRequest,un as prepareSiteEditHtmlInjectionRequest,Ge as resolveSiteEditBridgeHealthPath,Ft as resolveSiteEditClientAsset,ts as resolveSiteEditClientAssetPath,qe as resolveSiteEditNextDevBundler,on as runSiteEditRenderProbe,Xn as startSiteEditNextDevServer,en as transpileSiteEditClientSource};
package/dist/server.d.ts CHANGED
@@ -28,6 +28,11 @@ export type SiteEditBridgeServerOptions = {
28
28
  historyRoot?: string;
29
29
  allowedOrigins?: string[];
30
30
  runtime?: SiteEditBridgeRuntimeOptions;
31
+ /**
32
+ * 桥快照身份在运行期推进后的回调。调用顺序固定:runtime 已用新身份重建、
33
+ * 事件已广播之后才调用,供 dev server 把 health 的 launch.snapshotId 同步过去。
34
+ */
35
+ onSnapshotIdChanged?: (next: string, previous: string) => void;
31
36
  };
32
37
  /** @internal Dependency seam for deterministic runtime and durable-store tests. */
33
38
  export type SiteEditBridgeServerDependencies = {
@@ -64,6 +69,7 @@ export declare class SiteEditBridgeServer {
64
69
  private readonly pendingChangedFiles;
65
70
  private fileChangeTimer;
66
71
  private isStarted;
72
+ private stopping;
67
73
  private readonly runtimeVersionFloors;
68
74
  private activeHistoryStore;
69
75
  private versionPersistence;
@@ -80,6 +86,9 @@ export declare class SiteEditBridgeServer {
80
86
  private handleFileChanged;
81
87
  private handleFilesChanged;
82
88
  private flushChangedFiles;
89
+ private scheduleSnapshotIdentityAdvance;
90
+ private readCurrentSnapshotMarker;
91
+ private advanceSnapshotId;
83
92
  private refreshCompositions;
84
93
  private resolveComposition;
85
94
  private getInitialDocumentVersions;
@@ -98,6 +107,7 @@ declare function normalizeOptions(options: SiteEditBridgeServerOptions): {
98
107
  historyRoot: string | undefined;
99
108
  allowedOrigins: string[];
100
109
  runtime: SiteEditBridgeRuntimeOptions;
110
+ onSnapshotIdChanged: ((next: string, previous: string) => void) | undefined;
101
111
  };
102
112
  export declare function attachSiteEditWebSocketServer(options: {
103
113
  server: HttpServer;
package/dist/server.js CHANGED
@@ -1,4 +1,4 @@
1
- import me from"node:http";import A from"node:fs";import{createHash as Y,randomBytes as fe,timingSafeEqual as ge}from"node:crypto";import g from"node:path";import{WebSocket as Z,WebSocketServer as ye}from"ws";import{createPreviewSiteEditEngineRuntime as Ie,openFileHistoryStore as Se,resolveManagedPageTemplateComposition as we,scanSiteEditCompositionsFromFiles as Ce}from"@vcp-dev/site-edit-engine";import{resolveNextAppRouteId as xe,scanNextAppRouterRoutesFromFiles as Re}from"@vcp-dev/site-edit-engine/next-app-router";import{SiteEditSourceWatcher as Ee}from"@vcp-dev/site-edit-engine/source-watcher";function U(t){let e=new Map,s=[],i=new Map,o=[],n=t.pageComposition.status==="supported"?t.pageComposition.placementUnitKeys:[],r=new Map(n.map((u,h)=>[u,h])),a=t.pageComposition.status==="supported"?{status:"supported",containerKey:t.pageComposition.containerKey,hasBusinessMembers:t.pageComposition.hasBusinessMembers,placementUnitKeys:t.pageComposition.placementUnitKeys,placements:t.pageComposition.placements.map(u=>({placementKey:u.placementKey,placementUnitKey:u.placementUnitKey,relation:u.relation}))}:{status:"unsupported",reason:t.pageComposition.reason,diagnostics:t.pageComposition.diagnostics},c=t.entries.flatMap((u,h)=>u.dynamicDataSummary?[[h,u.dynamicDataSummary]]:[]),p=u=>{let h=e.get(u);if(typeof h=="number")return h;let C=s.length;return s.push(u),e.set(u,C),C},y=u=>{let h=null;for(let C of re(u)){let H=`${h??"root"}\0${C}`,V=i.get(H);if(typeof V=="number"){h=V;continue}let P=o.length;o.push([h,p(C)]),i.set(H,P),h=P}if(h===null)throw new Error("Document key must not be empty");return h};return{encoding:"segment-trie-v1",siteId:t.siteId,snapshotId:t.snapshotId,composition:{...t.composition},routeId:t.composition.routeId,version:t.version,pageComposition:a,tokens:s,nodes:o,entries:t.entries.map(u=>{let h=u.pageCompositionUnitKey?r.get(u.pageCompositionUnitKey)??-1:-1;if(u.pageCompositionUnitKey&&h<0)throw new Error(`Render entry ${u.key} references unknown page composition unit ${u.pageCompositionUnitKey}`);return[y(u.key),oe(u.operationSummary),...h>=0?[h]:[]]}),...c.length>0?{dynamicDataSummaries:c}:{}}}function oe(t){return(t.canUpdateText?1:0)|(t.canInsertChild?2:0)|(t.canMove?4:0)|(t.canRemove?8:0)}function re(t){if(!t)return[];let e=[],s=0,i=N(t,s);if(i<0)return e.push(t),e;for(e.push(t.slice(0,i)),s=i;s<t.length;){if(i=N(t,s+(t.startsWith("::",s)?2:1)),i<0){e.push(t.slice(s));break}e.push(t.slice(s,i)),s=i}return e}function N(t,e){let s=t.indexOf("/",e),i=t.indexOf("::",e);return s<0?i:i<0?s:Math.min(s,i)}var W="SITE_EDIT_COMPOSITION_SESSION_MISMATCH",M="SITE_EDIT_COMPOSITION_SESSION_REQUIRED";var l=class t{constructor(){}static parseMessage(e,s={}){let i=JSON.parse(e);if(!t.isMessage(i,s))throw new Error("Invalid site edit bridge message");return i}static stringifyMessage(e){return JSON.stringify(e)}static extractRequestInfo(e){if(d(e)&&d(e.payload)){let s=typeof e.payload.id=="string"?e.payload.id:"unknown",i=this.isRequestKind(e.payload.kind)?e.payload.kind:"get-document";return{id:s,kind:i}}return{id:"unknown",kind:"get-document"}}static isRequestKind(e){return e==="initialize-session"||e==="get-document"||e==="get-history-status"||e==="get-style-context"||e==="get-object-edit-context"||e==="get-class-name-source"||e==="get-source-tree"||e==="get-source-file"||e==="resolve-source-location"||e==="execute"||e==="undo"||e==="redo"}static isMessage(e,s={}){return!d(e)||typeof e.type!="string"?!1:e.type==="request"?ae(e.payload,s):e.type==="response"||e.type==="error"?d(e.payload)&&typeof e.payload.id=="string":e.type==="event"?d(e.payload)&&d(e.payload.event):e.type==="auth"?d(e.payload)&&typeof e.payload.key=="string":e.type==="auth-ok"&&d(e.payload)&&e.payload.ok===!0}},R=class{constructor(e){this.options=e,this.session={subscribedCompositionKeys:new Set},this.messageQueue=new D,this.eventDispatcher=new O(s=>{this.sendJson(s)}),this.unsubscribe=e.engine.subscribe(s=>{this.handleEngineEvent(s)}),e.socket.onmessage=s=>{try{this.messageQueue.enqueue(()=>this.handleRawMessage(s.data))}catch(i){this.sendJson({type:"error",payload:{id:"unknown",kind:"get-document",message:i instanceof Error?i.message:"Bridge queue overflow"}}),e.socket.close(1013,"bridge busy")}},e.socket.onclose=()=>{this.unsubscribe(),this.session.activeComposition=void 0,this.session.subscribedCompositionKeys.clear()}}async handleMessage(e){try{let s=e;if(s.type!=="request")return;let i=s.payload,{id:o}=i;switch(i.kind){case"initialize-session":{let n=v(i),r=await this.resolve(n),a=await this.options.engine.initializeSession({composition:r.context,...i.mutationContext?{mutationContext:i.mutationContext}:{}});this.activateSession(r.context),this.sendJson({type:"response",payload:{id:o,kind:i.kind,result:f({...a,data:{...a.data,document:z(a.data.document)}},r.context)}});return}case"get-document":{let n=await this.resolveWireContext(i),r=await this.options.engine.getDocument(n);this.sendResult(o,i.kind,pe(r,n));return}case"get-history-status":{let n=await this.resolveWireContext(i),r=await this.options.engine.getHistoryStatus(n);this.sendResult(o,i.kind,f(r,n));return}case"get-style-context":{let n=await this.resolveWireContext(i);this.sendResult(o,i.kind,f(await this.options.engine.getStyleContext(n),n));return}case"get-object-edit-context":{let n=await this.resolveWireContext(i);this.sendResult(o,i.kind,f(await this.options.engine.getObjectEditContext(i.key,n),n));return}case"get-class-name-source":{let n=await this.resolveWireContext(i);this.sendResult(o,i.kind,f(await this.options.engine.getClassNameSource(i.key,n),n));return}case"get-source-tree":{let n=await this.resolveWireContext(i);this.sendResult(o,i.kind,f(await this.options.engine.getSourceTree(n),n));return}case"get-source-file":{let n=await this.resolveWireContext(i);this.sendResult(o,i.kind,f(await this.options.engine.getSourceFile({path:i.path,composition:n}),n));return}case"resolve-source-location":{let n=await this.resolveWireContext(i),r=f(await this.options.engine.resolveSourceLocation({key:i.key,composition:n}),n);this.sendResult(o,i.kind,r);return}case"execute":{let n=await this.resolveOperationWireContext(i.request),r=await this.resolveWireContext(i);if(I(n)!==I(r))throw new S(W,"The execute request composition does not match its operation composition.");let a=await this.normalizeOperationRequest(i.request,n);await this.handleBufferedOperation(o,i.kind,()=>this.options.engine.execute(a));return}case"undo":case"redo":{let n=await this.resolveWireContext(i);await this.handleBufferedOperation(o,i.kind,()=>i.kind==="undo"?this.options.engine.undo(n):this.options.engine.redo(n));return}}}catch(s){let i=l.extractRequestInfo(e);this.sendJson({type:"error",payload:{...i,message:T(s),code:_(s)}})}}async resolve(e){return this.options.engine.resolveComposition(e)}async resolveAndAssert(e){let s=await this.resolve(e),i=this.session.activeComposition;if(!i)throw new S(M,"Initialize a composition session before issuing this request.");if(I(i)!==I(s.context))throw new S(W,"The request composition does not match the active socket session.");return s.context}async resolveWireContext(e){let s=v(e);return this.resolveAndAssert(s)}async resolveOperationWireContext(e){let s=de(e);return this.resolveAndAssert(s)}activateSession(e){this.session.activeComposition=e,this.session.subscribedCompositionKeys.clear(),this.session.subscribedCompositionKeys.add(I(e))}async normalizeOperationRequest(e,s){let i={...e,composition:j(s)};if(i.target.kind==="route"){let o=i.target,n=v(o),r=await this.resolveAndAssert(n);i.target={...o,composition:j(r)}}return i}handleEngineEvent(e){let s=e?.composition;if(!ue(s))return;let i=I(s);this.session.subscribedCompositionKeys.has(i)&&(this.eventDispatcher.push(e),e.type==="site-edit.graph.invalidated"&&i===he(this.session)&&(this.session.activeComposition=void 0,this.session.subscribedCompositionKeys.delete(i)))}sendResult(e,s,i){this.sendJson({type:"response",payload:{id:e,kind:s,result:i}})}async handleRawMessage(e){try{await this.handleMessage(l.parseMessage(e,{validateOperationRequest:this.options.validateOperationRequest}))}catch(s){let i=le(e);this.sendJson({type:"error",payload:{...i,message:T(s),code:_(s)}})}}sendJson(e){this.options.socket.send(l.stringifyMessage(e))}async handleBufferedOperation(e,s,i){this.eventDispatcher.beginBuffering();try{let o=await i();this.sendResult(e,s,o)}catch(o){this.sendJson({type:"error",payload:{id:e,kind:s,message:T(o),code:_(o)}})}finally{this.eventDispatcher.flush()}}},S=class extends Error{constructor(e,s){super(s),this.code=e,this.name="BridgeProtocolError"}},O=class{constructor(e){this.send=e,this.bufferedEvents=null}push(e){let s={type:"event",payload:{event:e}};if(this.bufferedEvents){this.bufferedEvents.push(s);return}this.send(s)}beginBuffering(){this.bufferedEvents=[]}flush(){let e=this.bufferedEvents??[];this.bufferedEvents=null,e.forEach(s=>this.send(s))}},D=class{constructor(e=64){this.maxQueued=e,this.queue=Promise.resolve(),this.queued=0}enqueue(e){if(this.queued>=this.maxQueued)throw new Error("Bridge request queue is full");this.queued+=1;let s=async()=>{this.queued-=1,await e()},i=this.queue.then(s,s);return this.queue=i.then(()=>{},()=>{}),i}};function ae(t,e){if(!d(t)||typeof t.id!="string"||!l.isRequestKind(t.kind))return!1;let s=x(t.composition);switch(t.kind){case"initialize-session":return s&&(t.mutationContext===void 0||k(t.mutationContext));case"get-document":case"get-style-context":return s;case"get-object-edit-context":case"get-class-name-source":case"resolve-source-location":return typeof t.key=="string"&&s;case"get-history-status":return s;case"get-source-tree":return s;case"get-source-file":return typeof t.path=="string"&&s;case"execute":return s&&ce(t.request)&&(t.request.mutationContext===void 0||k(t.request.mutationContext))&&(e.validateOperationRequest?.(t.request)??!0);case"undo":case"redo":return s&&t.mutationContext===void 0||s&&k(t.mutationContext)}}function ce(t){return d(t)&&typeof t.id=="string"&&typeof t.siteId=="string"&&typeof t.baseSnapshotId=="string"&&x(t.composition)&&typeof t.kind=="string"&&d(t.target)&&(t.target.kind!=="route"||x(t.target.composition))&&typeof t.documentVersion=="number"&&Number.isInteger(t.documentVersion)&&t.documentVersion>=0&&d(t.params)}function x(t){return d(t)&&typeof t.routeId=="string"&&t.routeId.length>0&&(t.templateId===void 0||typeof t.templateId=="string"&&t.templateId.length>0)&&Object.keys(t).every(e=>e==="routeId"||e==="templateId")}function ue(t){return d(t)&&typeof t.routeId=="string"&&(t.effectiveTemplateId===void 0||typeof t.effectiveTemplateId=="string")}function v(t){if(x(t.composition))return t.composition;throw new S(M,"A composition selector is required for this request.")}function de(t){if(d(t)&&x(t.composition))return t.composition;throw new S(M,"A composition selector is required for execute.")}function j(t){return{routeId:t.routeId,...t.effectiveTemplateId?{templateId:t.effectiveTemplateId}:{}}}function he(t){return t.activeComposition?I(t.activeComposition):null}function I(t){return JSON.stringify([t.routeId,t.effectiveTemplateId??null])}function f(t,e){return d(t)&&t.ok===!0?{...t,composition:e}:t}function pe(t,e){return!d(t)||t.ok!==!0?t:{...t,...e?{composition:e}:{},data:z(t.data)}}function z(t){let e=t;return U(e.routeId?e:{...e,routeId:e.composition.routeId})}function d(t){return typeof t=="object"&&t!==null}function k(t){return d(t)&&typeof t.editingSessionId=="string"&&t.editingSessionId.length>0&&typeof t.lockId=="string"&&t.lockId.length>0&&typeof t.ownerId=="string"&&t.ownerId.length>0&&typeof t.leaseAssertion=="string"&&t.leaseAssertion.length>0}function _(t){if(!(!d(t)||typeof t.code!="string"||t.code.length===0))return t.code}function T(t){return t instanceof Error||d(t)&&typeof t.message=="string"&&t.message.length>0?t.message:"Unknown websocket operation failure"}function le(t){try{return l.extractRequestInfo(JSON.parse(t))}catch{return{id:"unknown",kind:"get-document"}}}var E=class{constructor(){this.tail=Promise.resolve()}run(e){let s=this.tail.then(e,e);return this.tail=s.then(()=>{},()=>{}),s}};import{SiteEditOperationRequestSchema as be,computeSiteEditCompositionKey as w}from"@vcp-dev/contracts";var ve="127.0.0.1",ke=30218,_e="/__vcp/site-edit/bridge",X=6*1024*1024,Te=X*2,Oe=3e3,L=50,$="__VCP_SITE_EDIT_BRIDGE_SERVERS__";function nt(t){let e=ee(t),s=se(e),i=te(),o=i.get(s);if(o)return o;let n=new b(e);i.set(s,n);try{n.start()}catch(r){throw i.delete(s),n.stop(),r}return n}function ot(t,e,s={}){let i=new b(ee(e),t,!1,s);return i.start({listen:!1}),i}var b=class{constructor(e,s=me.createServer((n,r)=>{r.writeHead(404),r.end("VCP site edit bridge server")}),i=!0,o={}){this.options=e,this.server=s,this.closeHttpServerOnStop=i,this.dependencies=o,this.runtime=null,this.activeHistorySessionId=null,this.historySessionTransition=Promise.resolve(),this.mutationQueue=new E,this.eventListeners=new Set,this.routes=[],this.compositions=[],this.compositionFiles=[],this.compositionResolutionError=null,this.stopWatching=null,this.stopWebSocketServer=null,this.pendingChangedFiles=new Set,this.fileChangeTimer=null,this.isStarted=!1,this.runtimeVersionFloors=new Map,this.activeHistoryStore=null,this.versionPersistence=Promise.resolve()}start(e={}){if(this.isStarted)return;this.refreshCompositions(!0),this.isStarted=!0,this.createRuntime();let s=Be({server:this.server,path:this.options.path,sessionKey:this.options.sessionKey,host:this.options.host,allowedOrigins:this.options.allowedOrigins,engine:this.createBridgeEngine()});this.stopWebSocketServer=s.stop,this.stopWatching=new Ee({projectRoot:this.options.projectRoot,watch_dirs:De(this.options.runtime.watch_dirs),interval_ms:this.options.runtime.watch_interval_ms,debounce_ms:this.options.runtime.watch_debounce_ms??L,max_dirs:this.options.runtime.watch_max_dirs,max_files:this.options.runtime.watch_max_files,max_depth:this.options.runtime.watch_max_depth,max_startup_ms:this.options.runtime.watch_max_startup_ms,on_change:i=>this.handleFileChanged(i),on_batch_change:i=>this.handleFilesChanged(i)}).start(),e.listen!==!1&&this.server.listen(this.options.port,this.options.host)}getHealth(){let e=!!this.runtime&&!this.compositionResolutionError;return{ok:this.isStarted&&e,bridgePath:this.options.path,runtimeReady:e,routesIndexed:this.routes.length,sessionRequired:!!this.options.sessionKey}}stop(){this.stopWatching?.(),this.stopWatching=null,this.flushChangedFiles(),this.fileChangeTimer&&(clearTimeout(this.fileChangeTimer),this.fileChangeTimer=null),this.stopWebSocketServer?.(),this.stopWebSocketServer=null,this.runtime?.dispose(),this.runtime=null,this.compositions=[],this.compositionFiles=[],this.compositionResolutionError=null,this.closeHttpServerOnStop&&this.server.close();let e=te(),s=se(this.options);e.get(s)===this&&e.delete(s),this.isStarted=!1}createRuntime(e,s=null){let i=this.runtime;this.activeHistoryStore=e??null;let o=(this.dependencies.createRuntime??Ie)({...this.options.tenantId?{tenantId:this.options.tenantId}:{},siteId:this.options.siteId,snapshotId:this.options.snapshotId,projectRoot:this.options.projectRoot,compositions:this.compositions,onEvent:n=>{"version"in n&&typeof n.version=="number"&&this.recordRuntimeVersion(n.version,"composition"in n?n.composition:void 0);for(let r of this.eventListeners)r(n)},...e?{historyStore:e}:{},...this.getInitialDocumentVersions().length>0?{initialDocumentVersions:this.getInitialDocumentVersions()}:{}});this.runtime=o,this.activeHistorySessionId=s,i?.dispose()}createBridgeEngine(){return{resolveComposition:e=>this.resolveComposition(e),initializeSession:e=>this.mutationQueue.run(async()=>{let s=await this.bindHistorySession(this.options.snapshotId);if(!s.ok)throw new Error(`${s.code}: ${s.message}`);let i=Ae(e.composition),o=this.getRuntime(),n=m(i);await o.initializeComposition(n);let a=o.getDocument(n).data;await this.recordRuntimeVersion(a.version,i);let c=(await o.getHistoryStatus()).data;return{ok:!0,composition:i,data:{document:a,historyStatus:c}}}),getDocument:async e=>{let s=this.getRuntime(),i=m(e);await s.initializeComposition(i);let o=s.getDocument(i);return await this.recordRuntimeVersion(o.data.version,e),{...o,composition:e}},getHistoryStatus:async e=>({...await this.getRuntime().getHistoryStatus(),composition:e}),getStyleContext:async e=>this.getRuntime().getStyleContext(m(e)),getObjectEditContext:async(e,s)=>this.getRuntime().getObjectEditContext(e,m(s)),getClassNameSource:async(e,s)=>this.getRuntime().getClassNameSource(e,m(s)),getSourceTree:async e=>this.getRuntime().getSourceTree(m(e)),getSourceFile:async e=>this.getRuntime().getSourceFile({path:e.path,composition:m(e.composition)}),resolveSourceLocation:async e=>this.getRuntime().resolveSourceLocation({key:e.key,composition:m(e.composition)}),execute:(e,s)=>this.mutationQueue.run(async()=>{let i=await this.bindHistorySession(this.options.snapshotId);if(!i.ok)return F(i,e);let o=await this.getRuntime().executeOperation(e);return o.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(o.data.resultVersion,o.composition),o}),undo:e=>this.mutationQueue.run(async()=>{let s=await this.bindHistorySession(this.options.snapshotId);if(!s.ok)return F(s,void 0,e);let i=await this.getRuntime().undo();return i.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(i.data.resultVersion,i.composition??e),i.composition?i:{...i,composition:e}}),redo:e=>this.mutationQueue.run(async()=>{let s=await this.bindHistorySession(this.options.snapshotId);if(!s.ok)return F(s,void 0,e);let i=await this.getRuntime().redo();return i.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(i.data.resultVersion,i.composition??e),i.composition?i:{...i,composition:e}}),subscribe:e=>(this.eventListeners.add(e),()=>this.eventListeners.delete(e))}}async bindHistorySession(e){if(!this.options.historyRoot)return{ok:!1,code:"RECOVERY_PERSIST_FAILED",message:"Durable edit history is not configured."};if(this.activeHistorySessionId===e)return{ok:!0};let s=this.historySessionTransition.then(async()=>{if(this.activeHistorySessionId===e)return;let i=await(this.dependencies.openHistoryStore??Se)(Fe({root:this.options.historyRoot,siteId:this.options.siteId,snapshotId:this.options.snapshotId,editingSessionId:e}));if(!this.isStarted)return;let o=i.readDocumentVersion?await i.readDocumentVersion():0,n=this.compositions[0]?.context;if(n){let r=w(n);this.runtimeVersionFloors.set(r,Math.max(this.runtimeVersionFloors.get(r)??0,o))}this.createRuntime(i,e)});this.historySessionTransition=s.catch(()=>{});try{return await s,{ok:!0}}catch{return{ok:!1,code:"RECOVERY_PERSIST_FAILED",message:"Durable edit history could not be opened."}}}recordRuntimeVersion(e,s){let i=s?w(s):null;i&&this.runtimeVersionFloors.set(i,Math.max(this.runtimeVersionFloors.get(i)??0,e));let o=this.activeHistoryStore;if(!o?.writeDocumentVersion)return Promise.resolve();let n=i?this.runtimeVersionFloors.get(i)??e:e;return this.versionPersistence=this.versionPersistence.then(()=>o.writeDocumentVersion(n)).catch(()=>{}),this.versionPersistence}handleFileChanged(e){this.handleFilesChanged([e])}handleFilesChanged(e){for(let i of e)this.pendingChangedFiles.add(i);this.fileChangeTimer&&clearTimeout(this.fileChangeTimer);let s=this.options.runtime.watch_debounce_ms??L;this.fileChangeTimer=setTimeout(()=>{this.fileChangeTimer=null,this.flushChangedFiles()},s),this.fileChangeTimer?.unref?.()}flushChangedFiles(){if(this.fileChangeTimer&&(clearTimeout(this.fileChangeTimer),this.fileChangeTimer=null),this.pendingChangedFiles.size===0)return;let e=[...this.pendingChangedFiles].sort((s,i)=>s.localeCompare(i));if(this.pendingChangedFiles.clear(),!!this.refreshCompositions(!1))for(let s of e)this.runtime?.notifyFileChanged(s)}refreshCompositions(e=!1){try{let s=Me(this.options.projectRoot),i=Re(s),o=i.length>0?i:(this.options.runtime.routes??[]).map(c=>({...c})),n=Ce({files:s});if(n.length===0)throw new Error("No canonical App Router composition is indexed by the preview bridge.");let r=new Map(this.compositions.map(c=>[w(c.context),c])),a=new Map(n.map(c=>[w(c.context),c]));if(this.runtime){for(let[c,p]of r){let y=a.get(c);(!y||y.entryFile!==p.entryFile)&&this.runtime.unregisterComposition(m(p.context))}for(let[c,p]of a){let y=r.get(c);(!y||y.entryFile!==p.entryFile)&&this.runtime.registerComposition(p.context,p.entryFile)}}return this.routes=o,this.compositions=n,this.compositionFiles=s,this.compositionResolutionError=null,!0}catch(s){let i=s instanceof Error?s:new Error(String(s));if(this.compositionResolutionError=i,e)throw i;return!1}}resolveComposition(e){if(this.compositionResolutionError)throw this.compositionResolutionError;let s=xe(e.routeId,this.routes,this.options.basePath);if(!s)throw new Error(`Route is not indexed by the preview bridge: ${e.routeId}`);let i=this.routes.find(r=>r.routeId===s);if(!i)throw new Error(`Route is not indexed by the preview bridge: ${e.routeId}`);let o=we({selector:{routeId:s,...e.templateId?{templateId:e.templateId}:{}},files:this.compositionFiles,canonicalEntryFile:i.entryFile}),n=w(o.context);if(!this.compositions.some(r=>w(r.context)===n))throw new Error(`Composition is not registered by the preview bridge: ${n}`);return o}getInitialDocumentVersions(){return this.compositions.flatMap(e=>{let s=this.runtimeVersionFloors.get(w(e.context));return s===void 0?[]:[{composition:e.context,version:s}]})}getRuntime(){if(!this.runtime)throw new Error("VCP site edit preview bridge runtime is not ready");return this.runtime}};function ee(t){return{tenantId:t.tenantId,siteId:t.siteId,snapshotId:t.snapshotId,projectRoot:g.resolve(t.projectRoot??process.cwd()),basePath:t.basePath??"",host:t.host??ve,port:t.port??ke,path:t.path??_e,sessionKey:t.sessionKey??Ue(),historyRoot:t.historyRoot,allowedOrigins:t.allowedOrigins??[],runtime:t.runtime??{}}}function De(t){let e=["app","src/app","components/site","src/components/site","lib/generated","src/lib/generated","public"];return[...new Set([...t?.length?t:e,".vcp"])]}function Me(t){let e=[],s=["app","src/app",".vcp"],i=new Set([".git",".next",".turbo","coverage","dist","node_modules","output","snapshot-store"]),o=n=>{if(!A.existsSync(n))return;let r;try{r=A.readdirSync(n,{withFileTypes:!0})}catch{return}for(let a of r){if(a.name.startsWith(".")&&a.name!==".vcp")continue;if(a.isDirectory()){if(i.has(a.name))continue;o(g.join(n,a.name));continue}if(!a.isFile())continue;let c=g.join(n,a.name),p="";try{p=A.readFileSync(c,"utf8")}catch{}e.push({path:g.relative(t,c).replaceAll(g.sep,"/"),content:p})}};for(let n of s)o(g.join(t,n));return e.sort((n,r)=>n.path.localeCompare(r.path))}function Ae(t){if(!t||typeof t!="object"||typeof t.routeId!="string")throw new Error("Normalized composition context is required.");if("effectiveTemplateId"in t)return t;let e=t;return{routeId:e.routeId,...e.templateId?{effectiveTemplateId:e.templateId}:{}}}function m(t){return{routeId:t.routeId,...t.effectiveTemplateId?{templateId:t.effectiveTemplateId}:{}}}function Fe(t){return g.join(g.resolve(t.root),J(t.siteId),J(t.snapshotId),Y("sha256").update(t.editingSessionId).digest("hex").slice(0,32))}function J(t){return/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(t)&&t!=="."&&t!==".."?t:Y("sha256").update(t).digest("hex").slice(0,32)}function te(){let t=globalThis;return t[$]??=new Map,t[$]}function se(t){return`${t.projectRoot}:${t.host}:${t.port}:${t.path}:${t.historyRoot??""}`}function F(t,e,s){let i=s??(e?.composition?{routeId:e.composition.routeId,...e.composition.templateId?{effectiveTemplateId:e.composition.templateId}:{}}:void 0);if(!i)throw new Error("A normalized composition is required to construct a mutation result.");return{ok:!1,composition:i,error:{code:t.code,message:t.message},data:{requestId:e?.id??"mutation-context",kind:e?.kind??"update-text",composition:i,target:e?.target??{kind:"node",key:""},resultVersion:e?.documentVersion??0}}}function Be(t){let e=new ye({maxPayload:X,noServer:!0}),s=new WeakSet,i=n=>{new R({socket:new K(n),engine:t.engine,validateOperationRequest:r=>be.safeParse(r).success})},o=(n,r,a)=>{if(!Ke(n,t))return;let c=qe(n,t);if(!c){r.write(`HTTP/1.1 401 Unauthorized\r
1
+ import ft from"node:http";import x from"node:fs";import{createHash as Z,randomBytes as gt,timingSafeEqual as yt}from"node:crypto";import m from"node:path";import{WebSocket as X,WebSocketServer as It}from"ws";import{createPreviewSiteEditEngineRuntime as St,openFileHistoryStore as wt,resolveManagedPageTemplateComposition as Ct,scanSiteEditCompositionsFromFiles as Rt}from"@vcp-dev/site-edit-engine";import{resolveNextAppRouteId as xt,scanNextAppRouterRoutesFromFiles as Et}from"@vcp-dev/site-edit-engine/next-app-router";import{SiteEditSourceWatcher as vt}from"@vcp-dev/site-edit-engine/source-watcher";function $(e){let t=new Map,s=[],i=new Map,o=[],n=e.pageComposition.status==="supported"?e.pageComposition.placementUnitKeys:[],r=new Map(n.map((u,h)=>[u,h])),a=e.pageComposition.status==="supported"?{status:"supported",containerKey:e.pageComposition.containerKey,hasBusinessMembers:e.pageComposition.hasBusinessMembers,placementUnitKeys:e.pageComposition.placementUnitKeys,placements:e.pageComposition.placements.map(u=>({placementKey:u.placementKey,placementUnitKey:u.placementUnitKey,relation:u.relation}))}:{status:"unsupported",reason:e.pageComposition.reason,diagnostics:e.pageComposition.diagnostics},c=e.entries.flatMap((u,h)=>u.dynamicDataSummary?[[h,u.dynamicDataSummary]]:[]),p=u=>{let h=t.get(u);if(typeof h=="number")return h;let C=s.length;return s.push(u),t.set(u,C),C},y=u=>{let h=null;for(let C of at(u)){let P=`${h??"root"}\0${C}`,N=i.get(P);if(typeof N=="number"){h=N;continue}let U=o.length;o.push([h,p(C)]),i.set(P,U),h=U}if(h===null)throw new Error("Document key must not be empty");return h};return{encoding:"segment-trie-v1",siteId:e.siteId,snapshotId:e.snapshotId,composition:{...e.composition},routeId:e.composition.routeId,version:e.version,pageComposition:a,tokens:s,nodes:o,entries:e.entries.map(u=>{let h=u.pageCompositionUnitKey?r.get(u.pageCompositionUnitKey)??-1:-1;if(u.pageCompositionUnitKey&&h<0)throw new Error(`Render entry ${u.key} references unknown page composition unit ${u.pageCompositionUnitKey}`);return[y(u.key),rt(u.operationSummary),...h>=0?[h]:[]]}),...c.length>0?{dynamicDataSummaries:c}:{}}}function rt(e){return(e.canUpdateText?1:0)|(e.canInsertChild?2:0)|(e.canMove?4:0)|(e.canRemove?8:0)}function at(e){if(!e)return[];let t=[],s=0,i=W(e,s);if(i<0)return t.push(e),t;for(t.push(e.slice(0,i)),s=i;s<e.length;){if(i=W(e,s+(e.startsWith("::",s)?2:1)),i<0){t.push(e.slice(s));break}t.push(e.slice(s,i)),s=i}return t}function W(e,t){let s=e.indexOf("/",t),i=e.indexOf("::",t);return s<0?i:i<0?s:Math.min(s,i)}var j="SITE_EDIT_COMPOSITION_SESSION_MISMATCH",M="SITE_EDIT_COMPOSITION_SESSION_REQUIRED";var l=class e{constructor(){}static parseMessage(t,s={}){let i=JSON.parse(t);if(!e.isMessage(i,s))throw new Error("Invalid site edit bridge message");return i}static stringifyMessage(t){return JSON.stringify(t)}static extractRequestInfo(t){if(d(t)&&d(t.payload)){let s=typeof t.payload.id=="string"?t.payload.id:"unknown",i=this.isRequestKind(t.payload.kind)?t.payload.kind:"get-document";return{id:s,kind:i}}return{id:"unknown",kind:"get-document"}}static isRequestKind(t){return t==="initialize-session"||t==="get-document"||t==="get-history-status"||t==="get-style-context"||t==="get-object-edit-context"||t==="get-class-name-source"||t==="get-source-tree"||t==="get-source-file"||t==="resolve-source-location"||t==="execute"||t==="undo"||t==="redo"}static isMessage(t,s={}){return!d(t)||typeof t.type!="string"?!1:t.type==="request"?ct(t.payload,s):t.type==="response"||t.type==="error"?d(t.payload)&&typeof t.payload.id=="string":t.type==="event"?d(t.payload)&&d(t.payload.event):t.type==="auth"?d(t.payload)&&typeof t.payload.key=="string":t.type==="auth-ok"&&d(t.payload)&&t.payload.ok===!0}},E=class{constructor(t){this.options=t,this.session={subscribedCompositionKeys:new Set},this.messageQueue=new D,this.eventDispatcher=new A(s=>{this.sendJson(s)}),this.unsubscribe=t.engine.subscribe(s=>{this.handleEngineEvent(s)}),t.socket.onmessage=s=>{try{this.messageQueue.enqueue(()=>this.handleRawMessage(s.data))}catch(i){this.sendJson({type:"error",payload:{id:"unknown",kind:"get-document",message:i instanceof Error?i.message:"Bridge queue overflow"}}),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 s=t;if(s.type!=="request")return;let i=s.payload,{id:o}=i;switch(i.kind){case"initialize-session":{let n=k(i),r=await this.resolve(n),a=await this.options.engine.initializeSession({composition:r.context,...i.mutationContext?{mutationContext:i.mutationContext}:{}});this.activateSession(r.context),this.sendJson({type:"response",payload:{id:o,kind:i.kind,result:g({...a,data:{...a.data,document:L(a.data.document)}},r.context)}});return}case"get-document":{let n=await this.resolveWireContext(i),r=await this.options.engine.getDocument(n);this.sendResult(o,i.kind,lt(r,n));return}case"get-history-status":{let n=await this.resolveWireContext(i),r=await this.options.engine.getHistoryStatus(n);this.sendResult(o,i.kind,g(r,n));return}case"get-style-context":{let n=await this.resolveWireContext(i);this.sendResult(o,i.kind,g(await this.options.engine.getStyleContext(n),n));return}case"get-object-edit-context":{let n=await this.resolveWireContext(i);this.sendResult(o,i.kind,g(await this.options.engine.getObjectEditContext(i.key,n),n));return}case"get-class-name-source":{let n=await this.resolveWireContext(i);this.sendResult(o,i.kind,g(await this.options.engine.getClassNameSource(i.key,n),n));return}case"get-source-tree":{let n=await this.resolveWireContext(i);this.sendResult(o,i.kind,g(await this.options.engine.getSourceTree(n),n));return}case"get-source-file":{let n=await this.resolveWireContext(i);this.sendResult(o,i.kind,g(await this.options.engine.getSourceFile({path:i.path,composition:n}),n));return}case"resolve-source-location":{let n=await this.resolveWireContext(i),r=g(await this.options.engine.resolveSourceLocation({key:i.key,composition:n}),n);this.sendResult(o,i.kind,r);return}case"execute":{let n=await this.resolveOperationWireContext(i.request),r=await this.resolveWireContext(i);if(I(n)!==I(r))throw new S(j,"The execute request composition does not match its operation composition.");let a=await this.normalizeOperationRequest(i.request,n);await this.handleBufferedOperation(o,i.kind,()=>this.options.engine.execute(a));return}case"undo":case"redo":{let n=await this.resolveWireContext(i);await this.handleBufferedOperation(o,i.kind,()=>i.kind==="undo"?this.options.engine.undo(n):this.options.engine.redo(n));return}}}catch(s){let i=l.extractRequestInfo(t);this.sendJson({type:"error",payload:{...i,message:O(s),code:T(s)}})}}async resolve(t){return this.options.engine.resolveComposition(t)}async resolveAndAssert(t){let s=await this.resolve(t),i=this.session.activeComposition;if(!i)throw new S(M,"Initialize a composition session before issuing this request.");if(I(i)!==I(s.context))throw new S(j,"The request composition does not match the active socket session.");return s.context}async resolveWireContext(t){let s=k(t);return this.resolveAndAssert(s)}async resolveOperationWireContext(t){let s=ht(t);return this.resolveAndAssert(s)}activateSession(t){this.session.activeComposition=t,this.session.subscribedCompositionKeys.clear(),this.session.subscribedCompositionKeys.add(I(t))}async normalizeOperationRequest(t,s){let i={...t,composition:z(s)};if(i.target.kind==="route"){let o=i.target,n=k(o),r=await this.resolveAndAssert(n);i.target={...o,composition:z(r)}}return i}handleEngineEvent(t){let s=t?.composition;if(!dt(s))return;let i=I(s);this.session.subscribedCompositionKeys.has(i)&&(this.eventDispatcher.push(t),t.type==="site-edit.graph.invalidated"&&i===pt(this.session)&&(this.session.activeComposition=void 0,this.session.subscribedCompositionKeys.delete(i)))}sendResult(t,s,i){this.sendJson({type:"response",payload:{id:t,kind:s,result:i}})}async handleRawMessage(t){try{await this.handleMessage(l.parseMessage(t,{validateOperationRequest:this.options.validateOperationRequest}))}catch(s){let i=mt(t);this.sendJson({type:"error",payload:{...i,message:O(s),code:T(s)}})}}sendJson(t){this.options.socket.send(l.stringifyMessage(t))}async handleBufferedOperation(t,s,i){this.eventDispatcher.beginBuffering();try{let o=await i();this.sendResult(t,s,o)}catch(o){this.sendJson({type:"error",payload:{id:t,kind:s,message:O(o),code:T(o)}})}finally{this.eventDispatcher.flush()}}},S=class extends Error{constructor(t,s){super(s),this.code=t,this.name="BridgeProtocolError"}},A=class{constructor(t){this.send=t,this.bufferedEvents=null}push(t){let s={type:"event",payload:{event:t}};if(this.bufferedEvents){this.bufferedEvents.push(s);return}this.send(s)}beginBuffering(){this.bufferedEvents=[]}flush(){let t=this.bufferedEvents??[];this.bufferedEvents=null,t.forEach(s=>this.send(s))}},D=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 s=async()=>{this.queued-=1,await t()},i=this.queue.then(s,s);return this.queue=i.then(()=>{},()=>{}),i}};function ct(e,t){if(!d(e)||typeof e.id!="string"||!l.isRequestKind(e.kind))return!1;let s=R(e.composition);switch(e.kind){case"initialize-session":return s&&(e.mutationContext===void 0||_(e.mutationContext));case"get-document":case"get-style-context":return s;case"get-object-edit-context":case"get-class-name-source":case"resolve-source-location":return typeof e.key=="string"&&s;case"get-history-status":return s;case"get-source-tree":return s;case"get-source-file":return typeof e.path=="string"&&s;case"execute":return s&&ut(e.request)&&(e.request.mutationContext===void 0||_(e.request.mutationContext))&&(t.validateOperationRequest?.(e.request)??!0);case"undo":case"redo":return s&&e.mutationContext===void 0||s&&_(e.mutationContext)}}function ut(e){return d(e)&&typeof e.id=="string"&&typeof e.siteId=="string"&&typeof e.baseSnapshotId=="string"&&R(e.composition)&&typeof e.kind=="string"&&d(e.target)&&(e.target.kind!=="route"||R(e.target.composition))&&typeof e.documentVersion=="number"&&Number.isInteger(e.documentVersion)&&e.documentVersion>=0&&d(e.params)}function R(e){return d(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 dt(e){return d(e)&&typeof e.routeId=="string"&&(e.effectiveTemplateId===void 0||typeof e.effectiveTemplateId=="string")}function k(e){if(R(e.composition))return e.composition;throw new S(M,"A composition selector is required for this request.")}function ht(e){if(d(e)&&R(e.composition))return e.composition;throw new S(M,"A composition selector is required for execute.")}function z(e){return{routeId:e.routeId,...e.effectiveTemplateId?{templateId:e.effectiveTemplateId}:{}}}function pt(e){return e.activeComposition?I(e.activeComposition):null}function I(e){return JSON.stringify([e.routeId,e.effectiveTemplateId??null])}function g(e,t){return d(e)&&e.ok===!0?{...e,composition:t}:e}function lt(e,t){return!d(e)||e.ok!==!0?e:{...e,...t?{composition:t}:{},data:L(e.data)}}function L(e){let t=e;return $(t.routeId?t:{...t,routeId:t.composition.routeId})}function d(e){return typeof e=="object"&&e!==null}function _(e){return d(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 T(e){if(!(!d(e)||typeof e.code!="string"||e.code.length===0))return e.code}function O(e){return e instanceof Error||d(e)&&typeof e.message=="string"&&e.message.length>0?e.message:"Unknown websocket operation failure"}function mt(e){try{return l.extractRequestInfo(JSON.parse(e))}catch{return{id:"unknown",kind:"get-document"}}}var v=class{constructor(){this.tail=Promise.resolve()}run(t){let s=this.tail.then(t,t);return this.tail=s.then(()=>{},()=>{}),s}};import{SiteEditOperationRequestSchema as bt,computeSiteEditCompositionKey as w}from"@vcp-dev/contracts";var kt="127.0.0.1",_t=30218,Tt="/__vcp/site-edit/bridge",tt=6*1024*1024,Ot=tt*2,At=3e3,J=50,K=".vcp/current-snapshot.json",Q="__VCP_SITE_EDIT_BRIDGE_SERVERS__";function re(e){let t=et(e),s=it(t),i=st(),o=i.get(s);if(o)return o;let n=new b(t);i.set(s,n);try{n.start()}catch(r){throw i.delete(s),n.stop(),r}return n}function ae(e,t,s={}){let i=new b(et(t),e,!1,s);return i.start({listen:!1}),i}var b=class{constructor(t,s=ft.createServer((n,r)=>{r.writeHead(404),r.end("VCP site edit bridge server")}),i=!0,o={}){this.options=t,this.server=s,this.closeHttpServerOnStop=i,this.dependencies=o,this.runtime=null,this.activeHistorySessionId=null,this.historySessionTransition=Promise.resolve(),this.mutationQueue=new v,this.eventListeners=new Set,this.routes=[],this.compositions=[],this.compositionFiles=[],this.compositionResolutionError=null,this.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()}start(t={}){if(this.isStarted)return;this.stopping=!1;try{x.mkdirSync(m.join(this.options.projectRoot,".vcp"),{recursive:!0})}catch(i){console.warn(`[vcp-site-edit] failed to ensure .vcp directory: ${i instanceof Error?i.message:String(i)}`)}this.refreshCompositions(!0),this.isStarted=!0,this.createRuntime();let s=Kt({server:this.server,path:this.options.path,sessionKey:this.options.sessionKey,host:this.options.host,allowedOrigins:this.options.allowedOrigins,engine:this.createBridgeEngine()});this.stopWebSocketServer=s.stop,this.stopWatching=new vt({projectRoot:this.options.projectRoot,watch_dirs:Dt(this.options.runtime.watch_dirs),interval_ms:this.options.runtime.watch_interval_ms,debounce_ms:this.options.runtime.watch_debounce_ms??J,max_dirs:this.options.runtime.watch_max_dirs,max_files:this.options.runtime.watch_max_files,max_depth:this.options.runtime.watch_max_depth,max_startup_ms:this.options.runtime.watch_max_startup_ms,on_change:i=>this.handleFileChanged(i),on_batch_change:i=>this.handleFilesChanged(i)}).start(),t.listen!==!1&&this.server.listen(this.options.port,this.options.host)}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=st(),s=it(this.options);t.get(s)===this&&t.delete(s),this.isStarted=!1}createRuntime(t,s=null){let i=this.runtime;this.activeHistoryStore=t??null;let o=(this.dependencies.createRuntime??St)({...this.options.tenantId?{tenantId:this.options.tenantId}:{},siteId:this.options.siteId,snapshotId:this.options.snapshotId,projectRoot:this.options.projectRoot,compositions:this.compositions,onEvent:n=>{"version"in n&&typeof n.version=="number"&&this.recordRuntimeVersion(n.version,"composition"in n?n.composition:void 0);for(let r of this.eventListeners)r(n)},...t?{historyStore:t}:{},...this.getInitialDocumentVersions().length>0?{initialDocumentVersions:this.getInitialDocumentVersions()}:{}});this.runtime=o,this.activeHistorySessionId=s,i?.dispose()}createBridgeEngine(){return{resolveComposition:t=>this.resolveComposition(t),initializeSession:t=>this.mutationQueue.run(async()=>{let s=await this.bindHistorySession(this.options.snapshotId);if(!s.ok)throw new Error(`${s.code}: ${s.message}`);let i=Ft(t.composition),o=this.getRuntime(),n=f(i);await o.initializeComposition(n);let a=o.getDocument(n).data;await this.recordRuntimeVersion(a.version,i);let c=(await o.getHistoryStatus()).data;return{ok:!0,composition:i,data:{document:a,historyStatus:c}}}),getDocument:async t=>{let s=this.getRuntime(),i=f(t);await s.initializeComposition(i);let o=s.getDocument(i);return await this.recordRuntimeVersion(o.data.version,t),{...o,composition:t}},getHistoryStatus:async t=>({...await this.getRuntime().getHistoryStatus(),composition:t}),getStyleContext:async t=>this.getRuntime().getStyleContext(f(t)),getObjectEditContext:async(t,s)=>this.getRuntime().getObjectEditContext(t,f(s)),getClassNameSource:async(t,s)=>this.getRuntime().getClassNameSource(t,f(s)),getSourceTree:async t=>this.getRuntime().getSourceTree(f(t)),getSourceFile:async t=>this.getRuntime().getSourceFile({path:t.path,composition:f(t.composition)}),resolveSourceLocation:async t=>this.getRuntime().resolveSourceLocation({key:t.key,composition:f(t.composition)}),execute:(t,s)=>this.mutationQueue.run(async()=>{let i=await this.bindHistorySession(this.options.snapshotId);if(!i.ok)return F(i,t);let o=await this.getRuntime().executeOperation(t);return o.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(o.data.resultVersion,o.composition),o}),undo:t=>this.mutationQueue.run(async()=>{let s=await this.bindHistorySession(this.options.snapshotId);if(!s.ok)return F(s,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 s=await this.bindHistorySession(this.options.snapshotId);if(!s.ok)return F(s,void 0,t);let i=await this.getRuntime().redo();return i.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(i.data.resultVersion,i.composition??t),i.composition?i:{...i,composition:t}}),subscribe:t=>(this.eventListeners.add(t),()=>this.eventListeners.delete(t))}}async bindHistorySession(t){if(!this.options.historyRoot)return{ok:!1,code:"RECOVERY_PERSIST_FAILED",message:"Durable edit history is not configured."};if(this.activeHistorySessionId===t)return{ok:!0};let s=this.historySessionTransition.then(async()=>{if(this.activeHistorySessionId===t)return;let i=await(this.dependencies.openHistoryStore??wt)(Bt({root:this.options.historyRoot,siteId:this.options.siteId,snapshotId:this.options.snapshotId,editingSessionId:t}));if(!this.isStarted)return;let o=i.readDocumentVersion?await i.readDocumentVersion():0,n=this.compositions[0]?.context;if(n){let r=w(n);this.runtimeVersionFloors.set(r,Math.max(this.runtimeVersionFloors.get(r)??0,o))}this.createRuntime(i,t)});this.historySessionTransition=s.catch(()=>{});try{return await s,{ok:!0}}catch{return{ok:!1,code:"RECOVERY_PERSIST_FAILED",message:"Durable edit history could not be opened."}}}recordRuntimeVersion(t,s){let i=s?w(s):null;i&&this.runtimeVersionFloors.set(i,Math.max(this.runtimeVersionFloors.get(i)??0,t));let o=this.activeHistoryStore;if(!o?.writeDocumentVersion)return Promise.resolve();let n=i?this.runtimeVersionFloors.get(i)??t:t;return this.versionPersistence=this.versionPersistence.then(()=>o.writeDocumentVersion(n)).catch(()=>{}),this.versionPersistence}handleFileChanged(t){this.handleFilesChanged([t])}handleFilesChanged(t){for(let i of t)this.pendingChangedFiles.add(i);this.fileChangeTimer&&clearTimeout(this.fileChangeTimer);let s=this.options.runtime.watch_debounce_ms??J;this.fileChangeTimer=setTimeout(()=>{this.fileChangeTimer=null,this.flushChangedFiles()},s),this.fileChangeTimer?.unref?.()}flushChangedFiles(){if(this.fileChangeTimer&&(clearTimeout(this.fileChangeTimer),this.fileChangeTimer=null),this.pendingChangedFiles.size===0)return;let t=[...this.pendingChangedFiles].sort((s,i)=>s.localeCompare(i));if(this.pendingChangedFiles.clear(),t.some($t)&&this.scheduleSnapshotIdentityAdvance(),!!this.refreshCompositions(!1))for(let s of t)this.runtime?.notifyFileChanged(s)}scheduleSnapshotIdentityAdvance(){if(this.stopping||!this.isStarted)return;let t=this.readCurrentSnapshotMarker();!t||t===this.options.snapshotId||this.mutationQueue.run(()=>this.advanceSnapshotId(t)).catch(s=>{console.warn(`[vcp-site-edit] snapshot identity advance failed: ${s instanceof Error?s.message:String(s)}`)})}readCurrentSnapshotMarker(){try{let t=x.readFileSync(m.join(this.options.projectRoot,K),"utf8"),s=JSON.parse(t),i=typeof s.snapshot_id=="string"?s.snapshot_id:"";return!i||H(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 s=this.options.snapshotId;this.options.snapshotId=t;try{if(this.options.historyRoot){let o=await this.bindHistorySession(t);if(!o.ok)throw new Error(`${o.code}: ${o.message}`)}else this.createRuntime()}catch(o){this.options.snapshotId=s,console.warn(`[vcp-site-edit] snapshot identity advance rolled back to ${s}: ${o instanceof Error?o.message:String(o)}`);return}let i=new Date().toISOString();for(let o of this.compositions){let n={type:"site-edit.snapshot.changed",siteId:this.options.siteId,composition:o.context,snapshotId:t,previousSnapshotId:s,at:i};for(let r of this.eventListeners)try{r(n)}catch(a){console.warn(`[vcp-site-edit] snapshot.changed listener failed: ${a instanceof Error?a.message:String(a)}`)}}try{this.options.onSnapshotIdChanged?.(t,s)}catch(o){console.warn(`[vcp-site-edit] onSnapshotIdChanged callback failed: ${o instanceof Error?o.message:String(o)}`)}}refreshCompositions(t=!1){try{let s=Mt(this.options.projectRoot),i=Et(s),o=i.length>0?i:(this.options.runtime.routes??[]).map(c=>({...c})),n=Rt({files:s});if(n.length===0)throw new Error("No canonical App Router composition is indexed by the preview bridge.");let r=new Map(this.compositions.map(c=>[w(c.context),c])),a=new Map(n.map(c=>[w(c.context),c]));if(this.runtime){for(let[c,p]of r){let y=a.get(c);(!y||y.entryFile!==p.entryFile)&&this.runtime.unregisterComposition(f(p.context))}for(let[c,p]of a){let y=r.get(c);(!y||y.entryFile!==p.entryFile)&&this.runtime.registerComposition(p.context,p.entryFile)}}return this.routes=o,this.compositions=n,this.compositionFiles=s,this.compositionResolutionError=null,!0}catch(s){let i=s instanceof Error?s:new Error(String(s));if(this.compositionResolutionError=i,t)throw i;return!1}}resolveComposition(t){if(this.compositionResolutionError)throw this.compositionResolutionError;let s=xt(t.routeId,this.routes,this.options.basePath);if(!s)throw new Error(`Route is not indexed by the preview bridge: ${t.routeId}`);let i=this.routes.find(r=>r.routeId===s);if(!i)throw new Error(`Route is not indexed by the preview bridge: ${t.routeId}`);let o=Ct({selector:{routeId:s,...t.templateId?{templateId:t.templateId}:{}},files:this.compositionFiles,canonicalEntryFile:i.entryFile}),n=w(o.context);if(!this.compositions.some(r=>w(r.context)===n))throw new Error(`Composition is not registered by the preview bridge: ${n}`);return o}getInitialDocumentVersions(){return this.compositions.flatMap(t=>{let s=this.runtimeVersionFloors.get(w(t.context));return s===void 0?[]:[{composition:t.context,version:s}]})}getRuntime(){if(!this.runtime)throw new Error("VCP site edit preview bridge runtime is not ready");return this.runtime}};function et(e){return{tenantId:e.tenantId,siteId:e.siteId,snapshotId:e.snapshotId,projectRoot:m.resolve(e.projectRoot??process.cwd()),basePath:e.basePath??"",host:e.host??kt,port:e.port??_t,path:e.path??Tt,sessionKey:e.sessionKey??Wt(),historyRoot:e.historyRoot,allowedOrigins:e.allowedOrigins??[],runtime:e.runtime??{},onSnapshotIdChanged:e.onSnapshotIdChanged}}function Dt(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 Mt(e){let t=[],s=["app","src/app",".vcp"],i=new Set([".git",".next",".turbo","coverage","dist","node_modules","output","snapshot-store"]),o=n=>{if(!x.existsSync(n))return;let r;try{r=x.readdirSync(n,{withFileTypes:!0})}catch{return}for(let a of r){if(a.name.startsWith(".")&&a.name!==".vcp")continue;if(a.isDirectory()){if(i.has(a.name))continue;o(m.join(n,a.name));continue}if(!a.isFile())continue;let c=m.join(n,a.name),p="";try{p=x.readFileSync(c,"utf8")}catch{}t.push({path:m.relative(e,c).replaceAll(m.sep,"/"),content:p})}};for(let n of s)o(m.join(e,n));return t.sort((n,r)=>n.path.localeCompare(r.path))}function Ft(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 f(e){return{routeId:e.routeId,...e.effectiveTemplateId?{templateId:e.effectiveTemplateId}:{}}}function Bt(e){return m.join(m.resolve(e.root),H(e.siteId),H(e.snapshotId),Z("sha256").update(e.editingSessionId).digest("hex").slice(0,32))}function H(e){return/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(e)&&e!=="."&&e!==".."?e:Z("sha256").update(e).digest("hex").slice(0,32)}function st(){let e=globalThis;return e[Q]??=new Map,e[Q]}function it(e){return`${e.projectRoot}:${e.host}:${e.port}:${e.path}:${e.historyRoot??""}`}function F(e,t,s){let i=s??(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 Kt(e){let t=new It({maxPayload:tt,noServer:!0}),s=new WeakSet,i=n=>{new E({socket:new q(n),engine:e.engine,validateOperationRequest:r=>bt.safeParse(r).success})},o=(n,r,a)=>{if(!Ht(n,e))return;let c=qt(n,e);if(!c){r.write(`HTTP/1.1 401 Unauthorized\r
2
2
  Connection: close\r
3
3
  \r
4
- `),r.destroy();return}c.authenticatedByHeader&&s.add(n),e.handleUpgrade(n,r,a,p=>{e.emit("connection",p,n)})};return t.server.on("upgrade",o),e.on("connection",(n,r)=>{if(s.has(r)){i(n);return}He(n,t.sessionKey,()=>{i(n)})}),e.stop=()=>{t.server.off("upgrade",o);for(let n of e.clients)n.close(1001,"bridge stopped");e.close()},e}var K=class{constructor(e){this.socket=e,this.onmessage=null,this.onclose=null,e.on("error",()=>{}),e.on("message",s=>{this.onmessage?.({data:s.toString()})}),e.on("close",()=>{this.onclose?.()})}send(e){if(this.socket.readyState===Z.OPEN){if(this.socket.bufferedAmount+Buffer.byteLength(e,"utf8")>Te){this.socket.close(1013,"bridge backpressure");return}this.socket.send(e)}}close(e,s){this.socket.close(e,s)}};function Ke(t,e){return new URL(t.url??"/","http://localhost").pathname===e.path}function qe(t,e){if(new URL(t.url??"/","http://localhost").searchParams.has("vcp_bridge_key"))return null;let i=B(t.headers["x-vcp-site-edit-key"]),o=ie(i,e.sessionKey),n=B(t.headers.host),r=B(t.headers.origin);return n&&!Ve(n,e.host,r)?null:r?Ne(r,n,e.allowedOrigins)?{authenticatedByHeader:o}:null:o?{authenticatedByHeader:!0}:null}function He(t,e,s){let i=setTimeout(()=>{t.close(1008,"bridge authentication timeout")},Oe),o,n=()=>{clearTimeout(i),t.off("message",o),t.off("close",n)},r=()=>{n(),t.close(1008,"bridge authentication failed")};o=a=>{try{let c=l.parseMessage(a.toString());if(c.type!=="auth"||!ie(c.payload.key,e)){r();return}n(),t.readyState===Z.OPEN&&t.send(l.stringifyMessage({type:"auth-ok",payload:{ok:!0}})),s()}catch{r()}},t.on("message",o),t.on("close",n)}function ie(t,e){if(!t)return!1;let s=Buffer.from(t),i=Buffer.from(e);return s.length===i.length&&ge(s,i)}function Ve(t,e,s){let i=G(t),o=G(e);return i===o||Q(o)&&Q(i)&&(!s||q(s,t))||Pe(o)&&(!s||q(s,t))}function Pe(t){return t==="0.0.0.0"||t==="::"}function Q(t){return t==="localhost"||t==="127.0.0.1"||t==="::1"}function Ne(t,e,s){return s.includes(t)||(e?q(t,e):!1)}function q(t,e){try{return new URL(t).host===ne(e)}catch{return!1}}function G(t){let e=ne(t);return e.startsWith("[")?e.slice(1,e.indexOf("]")):e.split(":").length-1===1?e.split(":",1)[0]??"":e}function ne(t){return t.trim().toLowerCase()}function B(t){return Array.isArray(t)?t[0]:t}function Ue(){return fe(32).toString("base64url")}export{Te as SITE_EDIT_BRIDGE_MAX_BUFFERED_BYTES,X as SITE_EDIT_BRIDGE_MAX_PAYLOAD_BYTES,b as SiteEditBridgeServer,ot as attachSiteEditBridgeServer,Be as attachSiteEditWebSocketServer,nt as ensureSiteEditBridgeServerStarted};
4
+ `),r.destroy();return}c.authenticatedByHeader&&s.add(n),t.handleUpgrade(n,r,a,p=>{t.emit("connection",p,n)})};return e.server.on("upgrade",o),t.on("connection",(n,r)=>{if(s.has(r)){i(n);return}Vt(n,e.sessionKey,()=>{i(n)})}),t.stop=()=>{e.server.off("upgrade",o);for(let n of t.clients)n.close(1001,"bridge stopped");t.close()},t}var q=class{constructor(t){this.socket=t,this.onmessage=null,this.onclose=null,t.on("error",()=>{}),t.on("message",s=>{this.onmessage?.({data:s.toString()})}),t.on("close",()=>{this.onclose?.()})}send(t){if(this.socket.readyState===X.OPEN){if(this.socket.bufferedAmount+Buffer.byteLength(t,"utf8")>Ot){this.socket.close(1013,"bridge backpressure");return}this.socket.send(t)}}close(t,s){this.socket.close(t,s)}};function Ht(e,t){return new URL(e.url??"/","http://localhost").pathname===t.path}function qt(e,t){if(new URL(e.url??"/","http://localhost").searchParams.has("vcp_bridge_key"))return null;let i=B(e.headers["x-vcp-site-edit-key"]),o=nt(i,t.sessionKey),n=B(e.headers.host),r=B(e.headers.origin);return n&&!Pt(n,t.host,r)?null:r?Ut(r,n,t.allowedOrigins)?{authenticatedByHeader:o}:null:o?{authenticatedByHeader:!0}:null}function Vt(e,t,s){let i=setTimeout(()=>{e.close(1008,"bridge authentication timeout")},At),o,n=()=>{clearTimeout(i),e.off("message",o),e.off("close",n)},r=()=>{n(),e.close(1008,"bridge authentication failed")};o=a=>{try{let c=l.parseMessage(a.toString());if(c.type!=="auth"||!nt(c.payload.key,t)){r();return}n(),e.readyState===X.OPEN&&e.send(l.stringifyMessage({type:"auth-ok",payload:{ok:!0}})),s()}catch{r()}},e.on("message",o),e.on("close",n)}function nt(e,t){if(!e)return!1;let s=Buffer.from(e),i=Buffer.from(t);return s.length===i.length&&yt(s,i)}function Pt(e,t,s){let i=Y(e),o=Y(t);return i===o||G(o)&&G(i)&&(!s||V(s,e))||Nt(o)&&(!s||V(s,e))}function Nt(e){return e==="0.0.0.0"||e==="::"}function G(e){return e==="localhost"||e==="127.0.0.1"||e==="::1"}function Ut(e,t,s){return s.includes(e)||(t?V(e,t):!1)}function V(e,t){try{return new URL(e).host===ot(t)}catch{return!1}}function Y(e){let t=ot(e);return t.startsWith("[")?t.slice(1,t.indexOf("]")):t.split(":").length-1===1?t.split(":",1)[0]??"":t}function ot(e){return e.trim().toLowerCase()}function B(e){return Array.isArray(e)?e[0]:e}function Wt(){return gt(32).toString("base64url")}function $t(e){let t=e.replaceAll("\\","/");return t===K||t.endsWith(`/${K}`)}export{Ot as SITE_EDIT_BRIDGE_MAX_BUFFERED_BYTES,tt as SITE_EDIT_BRIDGE_MAX_PAYLOAD_BYTES,b as SiteEditBridgeServer,ae as attachSiteEditBridgeServer,Kt as attachSiteEditWebSocketServer,re as ensureSiteEditBridgeServerStarted};
@@ -19,6 +19,12 @@ export declare function createVcpWindowMessageEnvelope<TNamespace extends string
19
19
  export declare function isVcpWindowMessageEnvelope(value: unknown): value is VcpWindowMessageEnvelope;
20
20
  export declare const SITE_EDIT_WINDOW_MESSAGE_NAMESPACE = "site-edit";
21
21
  export declare const SITE_EDIT_FRAME_RUNTIME_CHANNEL = "frame-runtime";
22
+ /**
23
+ * 嵌入运行时用来喊「我起来了」的独立通道。它不带 sessionKey,父页只能把它当
24
+ * 作「重发探针」的信号,绝不能当数据用——所以它必须与已认证的 frame-runtime
25
+ * 协议分开,两边的 type guard 互不接受对方通道的消息。
26
+ */
27
+ export declare const SITE_EDIT_FRAME_ANNOUNCE_CHANNEL = "frame-announce";
22
28
  export declare const SITE_EDIT_FRAME_RUNTIME_LAYOUT_SNAPSHOT_VERSION = 1;
23
29
  export declare const SITE_EDIT_FRAME_RUNTIME_SELECTION_VISUAL_VERSION = 1;
24
30
  export declare const SITE_EDIT_FRAME_RUNTIME_RESIZE_VISUAL_VERSION = 1;
@@ -564,5 +570,11 @@ export type SiteEditFrameRuntimeEventMessage = SiteEditFrameRuntimeMessage & {
564
570
  export declare function createSiteEditFrameRuntimeMessage(body: SiteEditFrameRuntimeBody, options?: {
565
571
  sessionKey?: string;
566
572
  }): SiteEditFrameRuntimeMessage;
573
+ export type SiteEditFrameAnnounceBody = {
574
+ type: "announce";
575
+ };
576
+ export type SiteEditFrameAnnounceMessage = VcpWindowMessageEnvelope<typeof SITE_EDIT_WINDOW_MESSAGE_NAMESPACE, typeof SITE_EDIT_FRAME_ANNOUNCE_CHANNEL, SiteEditFrameAnnounceBody>;
577
+ export declare function createSiteEditFrameAnnounceMessage(): SiteEditFrameAnnounceMessage;
578
+ export declare function isSiteEditFrameAnnounceMessage(value: unknown): value is SiteEditFrameAnnounceMessage;
567
579
  export declare function isSiteEditFrameRuntimeMessage(value: unknown): value is SiteEditFrameRuntimeMessage;
568
580
  export declare function isSiteEditFrameRuntimeLayoutSnapshot(value: unknown): value is SiteEditFrameRuntimeLayoutSnapshot;
@@ -1 +1 @@
1
- function S(e){return JSON.stringify([e.routeId,e.effectiveTemplateId??null])}var T="vcp-window-message",F=1;function B(e){return{source:T,version:F,namespace:e.namespace,channel:e.channel,...e.sessionKey?{sessionKey:e.sessionKey}:{},body:e.body}}function G(e){try{return i(e)?d(e,"source",T)&&d(e,"version",F)&&o(e,"namespace")&&o(e,"channel")&&f(e,"body")&&(!h(e,"sessionKey")||o(e,"sessionKey")):!1}catch{return!1}}var V="site-edit",C="frame-runtime",z=1,A=1,N=1,le=24;function ge(e,r={}){return B({namespace:V,channel:C,sessionKey:r.sessionKey,body:e})}function he(e){try{return!G(e)||e.namespace!==V||e.channel!==C?!1:ue(e.body)}catch{return!1}}function y(e){return i(e)&&o(e,"routeId")&&g(e,"templateId")&&m(e,["routeId","templateId"])}function R(e){return i(e)&&o(e,"routeId")&&g(e,"effectiveTemplateId")&&m(e,["routeId","effectiveTemplateId"])}function m(e,r){let t=new Set(r);return Reflect.ownKeys(e).every(s=>typeof s=="string"&&t.has(s))}var h=(e,r)=>Object.prototype.hasOwnProperty.call(e,r);function f(e,r){let t=Object.getOwnPropertyDescriptor(e,r);return t!==void 0&&"value"in t}function n(e,r){return Object.getOwnPropertyDescriptor(e,r)?.value}function d(e,r,t){return f(e,r)&&n(e,r)===t}function o(e,r){return f(e,r)&&typeof n(e,r)=="string"}function _(e,r){return f(e,r)&&typeof n(e,r)=="boolean"}function c(e,r){let t=n(e,r);return f(e,r)&&typeof t=="number"&&Number.isFinite(t)}function q(e,r){let t=n(e,r);return f(e,r)&&typeof t=="number"&&Number.isInteger(t)&&t>0}function g(e,r){return!h(e,r)||n(e,r)===void 0||o(e,r)}function b(e,r){return!h(e,r)||n(e,r)===void 0||c(e,r)}function w(e,r){let t=n(e,r);return!h(e,r)||t===void 0||f(e,r)&&typeof t=="number"&&Number.isInteger(t)&&t>=0}function a(e,r){return!h(e,r)||n(e,r)===void 0}function i(e){if(typeof e!="object"||e===null||Array.isArray(e))return!1;let r=Object.getPrototypeOf(e);return r===Object.prototype||r===null}function U(e){return i(e)&&Reflect.ownKeys(e).length===0}function O(e){if(!Array.isArray(e))return!1;for(let r=0;r<e.length;r+=1){let t=Object.getOwnPropertyDescriptor(e,String(r));if(t===void 0||!("value"in t)||typeof t.value!="string")return!1}return!0}function u(e){return i(e)&&o(e,"key")&&w(e,"instanceIndex")&&w(e,"instanceCount")&&w(e,"textSegmentIndex")}function j(e){return i(e)&&o(e,"blockId")&&u(n(e,"ref"))&&E(n(e,"rect"))&&_(e,"targetIsSectionRoot")}function H(e){if(!i(e))return!1;let r=n(e,"placement"),t=n(e,"boundary");return o(e,"anchorBlockId")&&u(n(e,"anchorRef"))&&(r==="before"||r==="after")&&i(t)&&c(t,"top")&&c(t,"left")&&c(t,"width")}function E(e){return i(e)&&["top","left","width","height"].every(r=>c(e,r))}function P(e){if(!i(e))return!1;let r=n(e,"rect"),t=n(e,"layout"),s=i(t)?n(t,"containingBlock"):null,p=n(e,"scrollContext"),l=i(s)&&(d(s,"kind","viewport")&&Reflect.ownKeys(s).length===1||d(s,"kind","document")&&Reflect.ownKeys(s).length===1||d(s,"kind","element")&&o(s,"runtimeNodeId"));return d(e,"version",z)&&o(e,"runtimeNodeId")&&i(r)&&E(n(r,"viewport"))&&E(n(r,"document"))&&i(t)&&o(t,"position")&&o(t,"transform")&&l&&i(p)&&["scrollX","scrollY","viewportWidth","viewportHeight"].every(I=>c(p,I))&&f(p,"scrollContainers")&&X(n(p,"scrollContainers"))}function X(e){return Array.isArray(e)&&e.every(r=>i(r)&&o(r,"runtimeNodeId")&&c(r,"scrollLeft")&&c(r,"scrollTop"))}function x(e){return i(e)&&(a(e,"layoutSnapshot")||P(n(e,"layoutSnapshot")))}function Y(e){return i(e)&&u(n(e,"ref"))&&f(e,"layoutSnapshot")&&P(n(e,"layoutSnapshot"))&&(a(e,"childBoxes")||J(n(e,"childBoxes")))&&(a(e,"childRects")||Z(n(e,"childRects")))&&(a(e,"layout")||k(n(e,"layout")))&&(a(e,"spacing")||Q(n(e,"spacing")))}function k(e){if(!i(e))return!1;let r=n(e,"indicatorOrientation");return o(e,"display")&&(r==="horizontal"||r==="vertical")&&g(e,"flexDirection")&&g(e,"gridAutoFlow")}function Z(e){return Array.isArray(e)&&e.every(r=>E(r))}function J(e){return Array.isArray(e)&&e.every(r=>i(r)&&E(n(r,"rect"))&&D(n(r,"margin")))}function D(e){return i(e)&&["marginTop","marginRight","marginBottom","marginLeft"].every(r=>c(e,r))}function Q(e){return D(e)&&["paddingTop","paddingRight","paddingBottom","paddingLeft","borderTopWidth","borderRightWidth","borderBottomWidth","borderLeftWidth","columnGap","rowGap"].every(r=>c(e,r))}function $(e){if(!Array.isArray(e))return!1;for(let r=0;r<e.length;r+=1){let t=Object.getOwnPropertyDescriptor(e,String(r));if(t===void 0||!("value"in t)||!Y(t.value))return!1}return!0}function v(e){return i(e)&&Reflect.ownKeys(e).every(r=>typeof r=="string"&&f(e,r)&&(typeof n(e,r)=="string"||n(e,r)===null))}function K(e){return e==null||typeof e=="string"||typeof e=="number"&&Number.isFinite(e)}function ee(e){return i(e)&&Reflect.ownKeys(e).every(r=>typeof r=="string"&&f(e,r)&&K(n(e,r)))}function te(e){if(!i(e))return!1;let r=n(e,"priority");return o(e,"property")&&f(e,"value")&&K(n(e,"value"))&&(!h(e,"priority")||r===void 0||r==="important")}function re(e){return i(e)?(a(e,"attributes")||v(n(e,"attributes")))&&g(e,"className")&&(a(e,"style")||ee(n(e,"style")))&&(a(e,"styleDeclarations")||Array.isArray(n(e,"styleDeclarations"))&&n(e,"styleDeclarations").every(te)):!1}function ne(e){return i(e)&&c(e,"x")&&c(e,"y")&&(a(e,"detailLevel")||d(e,"detailLevel","summary")||d(e,"detailLevel","full"))}function ie(e){return i(e)&&u(n(e,"ref"))}function oe(e){if(!i(e)||!i(n(e,"variables")))return!1;let r=n(e,"variables");return Reflect.ownKeys(r).every(t=>typeof t=="string"&&o(r,t))?a(e,"stylesheets")||O(n(e,"stylesheets")):!1}function se(e){if(!d(e,"type","request")||!o(e,"id")||!o(e,"kind")||!f(e,"payload"))return!1;let r=n(e,"kind"),t=n(e,"payload");switch(r){case"hit-test-at-point":case"start-text-edit-at-point":return ne(t);case"bridge-get-source-tree":return i(t)&&y(n(t,"composition"))&&m(t,["composition"]);case"get-scroll-metrics":case"clear-theme-override":return U(t);case"bridge-get-history-status":case"bridge-undo":case"bridge-redo":return i(t)&&y(n(t,"composition"))&&m(t,["composition"]);case"bridge-get-source-file":return i(t)&&o(t,"path")&&y(n(t,"composition"))&&m(t,["path","composition"]);case"bridge-resolve-source-location":case"bridge-get-object-edit-context":case"bridge-get-class-name-source":return i(t)&&o(t,"key")&&y(n(t,"composition"))&&m(t,["key","composition"]);case"scroll-to":return i(t)&&c(t,"x")&&c(t,"y");case"scroll-by":return i(t)&&c(t,"deltaX")&&c(t,"deltaY");case"set-interaction-mode":return i(t)&&_(t,"enabled");case"set-selection-visual":return i(t)&&d(t,"version",A)&&u(n(t,"ref"))&&d(t,"visible",!0);case"clear-selection-visual":return i(t)&&d(t,"version",A);case"set-resize-visual":return i(t)&&d(t,"version",N)&&u(n(t,"ref"))&&d(t,"visible",!0);case"clear-resize-visual":return i(t)&&d(t,"version",N);case"set-theme-override":return oe(t);case"get-theme-variables":return i(t)&&O(n(t,"names"));case"compute-drop-target-at-point":return i(t)&&c(t,"x")&&c(t,"y")&&(d(t,"dragKind","insert")||d(t,"dragKind","move"))&&(a(t,"movingRef")||u(n(t,"movingRef")));case"observe-node-bounds":case"clear-node-bounds-observer":return i(t)&&(a(t,"ref")||u(n(t,"ref")));case"apply-node-patch":return i(t)&&u(n(t,"ref"))&&re(n(t,"patch"))&&(a(t,"preview")||i(n(t,"preview"))&&o(n(t,"preview"),"sessionId")&&w(n(t,"preview"),"revision")&&h(n(t,"preview"),"revision"));case"get-hit-by-ref":case"get-path-by-ref":case"restore-text-edit":case"clear-text-edit-rollback":return ie(t);case"bridge-initialize-session":case"bridge-get-style-context":return i(t)&&y(n(t,"composition"))&&m(t,["composition"]);case"bridge-get-document":case"bridge-ensure-document-version":case"bridge-acknowledge-document-version":return i(t)&&y(n(t,"composition"))&&b(t,"minVersion")&&b(t,"version")&&m(t,["composition","minVersion","version"]);case"bridge-execute":{if(!i(t))return!1;let s=n(t,"request"),p=n(t,"composition"),l=i(s)?n(s,"composition"):null;return!y(p)||!i(s)||!y(l)?!1:S({routeId:p.routeId,...p.templateId?{effectiveTemplateId:p.templateId}:{}})===S({routeId:l.routeId,...l.templateId?{effectiveTemplateId:l.templateId}:{}})&&m(t,["composition","request"])}case"bridge-subscribe":case"bridge-unsubscribe":return i(t)&&o(t,"subscriptionId")&&y(n(t,"composition"))&&m(t,["subscriptionId","composition"]);default:return!1}}function ce(e){return d(e,"type","response")&&o(e,"id")&&_(e,"ok")&&(a(e,"error")||o(e,"error"))}function ae(e){if(!i(e))return!1;let r=n(e,"type");if(typeof r!="string"||!R(n(e,"composition"))||!o(e,"siteId")||!o(e,"at"))return!1;switch(r){case"site-edit.document.changed":return o(e,"snapshotId")&&c(e,"version");case"site-edit.operation.planned":return o(e,"operationId")&&o(e,"baseSnapshotId")&&O(n(e,"changedFiles"));case"site-edit.operation.completed":return i(n(e,"result"));case"site-edit.operation.failed":return o(e,"requestId")&&i(n(e,"error"));case"site-edit.capability.changed":return O(n(e,"keys"));case"site-edit.graph.invalidated":return!0;case"site-edit.graph.ready":return c(e,"version");case"site-edit.graph.error":return o(e,"message");default:return!1}}var de=new Set(["pointer-down","pointer-move","pointer-leave","pointer-up","pointer-cancel","pointer-click","pointer-double-click"]),M=new Set(["e","s","se"]);function pe(e,r){if(a(e,"resizeSession"))return!0;let t=n(e,"resizeSession");if(!i(t))return!1;let s=n(e,"pointerId"),p=n(t,"pointerId"),l=n(t,"phase"),I=n(t,"edge"),L=r==="pointer-down"?"start":r==="pointer-up"?"commit":r==="pointer-cancel"?"cancel":null;return n(t,"version")===1&&l===L&&o(t,"sessionId")&&String(n(t,"sessionId")).length>0&&typeof s=="number"&&Number.isInteger(s)&&typeof p=="number"&&Number.isInteger(p)&&s===p&&typeof I=="string"&&M.has(I)&&n(e,"resizeEdge")===I&&u(n(t,"ref"))&&["startWidth","startHeight","width","height"].every(W=>c(t,W))}function fe(e){if(!d(e,"type","event")||!o(e,"kind")||!i(n(e,"payload")))return!1;let r=n(e,"kind"),t=n(e,"payload");switch(r){case"text-edit-commit":case"text-edit-cancel":case"text-edit-exit":case"text-edit-input":return u(n(t,"ref"))&&g(t,"value")&&(a(t,"hit")||x(n(t,"hit")));case"node-bounds-change":return x(n(t,"hit"));case"geometry-batch":{let s=n(t,"reason");return q(t,"sequence")&&c(t,"sourceEventAt")&&c(t,"captureStartedAt")&&c(t,"capturedAt")&&(s==="scroll"||s==="resize"||s==="mutation")&&$(n(t,"snapshots"))}case"bridge-event":{let s=n(t,"event"),p=n(t,"composition");return!ae(s)||!R(p)?!1:o(t,"subscriptionId")&&S(p)===S(s.composition)}case"route-ready":return R(n(t,"composition"))&&o(t,"editEngineVersion")&&c(t,"sequence")&&c(t,"version");case"bridge-status":{let s=n(t,"state");return(s==="connecting"||s==="ready"||s==="reconnecting"||s==="failed"||s==="reload-required")&&R(n(t,"composition"))&&c(t,"sequence")&&b(t,"attempt")&&b(t,"retryInMs")&&g(t,"messageKey")}case"scroll":{let s=n(t,"metrics");return i(s)&&["scrollX","scrollY","scrollWidth","scrollHeight","viewportWidth","viewportHeight"].every(p=>c(s,p))}default:return de.has(r)&&c(t,"clientX")&&c(t,"clientY")&&b(t,"buttons")&&b(t,"pointerId")&&(a(t,"hoverVisualOwned")||_(t,"hoverVisualOwned"))&&(a(t,"resizeEdge")||o(t,"resizeEdge")&&M.has(n(t,"resizeEdge")))&&pe(t,r)&&(n(t,"hit")===null||x(n(t,"hit")))&&(a(t,"section")||n(t,"section")===null||j(n(t,"section")))&&(a(t,"sectionGap")||n(t,"sectionGap")===null||H(n(t,"sectionGap")))}}function ue(e){if(!i(e))return!1;switch(n(e,"type")){case"request":return se(e);case"response":return ce(e);case"event":return fe(e);default:return!1}}export{C as SITE_EDIT_FRAME_RUNTIME_CHANNEL,z as SITE_EDIT_FRAME_RUNTIME_LAYOUT_SNAPSHOT_VERSION,N as SITE_EDIT_FRAME_RUNTIME_RESIZE_VISUAL_VERSION,A as SITE_EDIT_FRAME_RUNTIME_SELECTION_VISUAL_VERSION,le as SITE_EDIT_FRAME_SECTION_GAP_RADIUS_PX,V as SITE_EDIT_WINDOW_MESSAGE_NAMESPACE,T as VCP_WINDOW_MESSAGE_SOURCE,F as VCP_WINDOW_MESSAGE_VERSION,ge as createSiteEditFrameRuntimeMessage,B as createVcpWindowMessageEnvelope,P as isSiteEditFrameRuntimeLayoutSnapshot,he as isSiteEditFrameRuntimeMessage,G as isVcpWindowMessageEnvelope};
1
+ function S(e){return JSON.stringify([e.routeId,e.effectiveTemplateId??null])}var F="vcp-window-message",C=1;function V(e){return{source:F,version:C,namespace:e.namespace,channel:e.channel,...e.sessionKey?{sessionKey:e.sessionKey}:{},body:e.body}}function D(e){try{return i(e)?a(e,"source",F)&&a(e,"version",C)&&o(e,"namespace")&&o(e,"channel")&&f(e,"body")&&(!h(e,"sessionKey")||o(e,"sessionKey")):!1}catch{return!1}}var _="site-edit",P="frame-runtime",M="frame-announce",q=1,N=1,T=1,le=24;function he(e,n={}){return V({namespace:_,channel:P,sessionKey:n.sessionKey,body:e})}function be(){return V({namespace:_,channel:M,body:{type:"announce"}})}function Ie(e){try{return!D(e)||e.namespace!==_||e.channel!==M?!1:i(e.body)&&a(e.body,"type","announce")&&u(e.body,["type"])}catch{return!1}}function Se(e){try{return!D(e)||e.namespace!==_||e.channel!==P?!1:me(e.body)}catch{return!1}}function y(e){return i(e)&&o(e,"routeId")&&l(e,"templateId")&&u(e,["routeId","templateId"])}function R(e){return i(e)&&o(e,"routeId")&&l(e,"effectiveTemplateId")&&u(e,["routeId","effectiveTemplateId"])}function u(e,n){let t=new Set(n);return Reflect.ownKeys(e).every(s=>typeof s=="string"&&t.has(s))}var h=(e,n)=>Object.prototype.hasOwnProperty.call(e,n);function f(e,n){let t=Object.getOwnPropertyDescriptor(e,n);return t!==void 0&&"value"in t}function r(e,n){return Object.getOwnPropertyDescriptor(e,n)?.value}function a(e,n,t){return f(e,n)&&r(e,n)===t}function o(e,n){return f(e,n)&&typeof r(e,n)=="string"}function x(e,n){return f(e,n)&&typeof r(e,n)=="boolean"}function c(e,n){let t=r(e,n);return f(e,n)&&typeof t=="number"&&Number.isFinite(t)}function U(e,n){let t=r(e,n);return f(e,n)&&typeof t=="number"&&Number.isInteger(t)&&t>0}function l(e,n){return!h(e,n)||r(e,n)===void 0||o(e,n)}function b(e,n){return!h(e,n)||r(e,n)===void 0||c(e,n)}function w(e,n){let t=r(e,n);return!h(e,n)||t===void 0||f(e,n)&&typeof t=="number"&&Number.isInteger(t)&&t>=0}function d(e,n){return!h(e,n)||r(e,n)===void 0}function i(e){if(typeof e!="object"||e===null||Array.isArray(e))return!1;let n=Object.getPrototypeOf(e);return n===Object.prototype||n===null}function j(e){return i(e)&&Reflect.ownKeys(e).length===0}function O(e){if(!Array.isArray(e))return!1;for(let n=0;n<e.length;n+=1){let t=Object.getOwnPropertyDescriptor(e,String(n));if(t===void 0||!("value"in t)||typeof t.value!="string")return!1}return!0}function m(e){return i(e)&&o(e,"key")&&w(e,"instanceIndex")&&w(e,"instanceCount")&&w(e,"textSegmentIndex")}function H(e){return i(e)&&o(e,"blockId")&&m(r(e,"ref"))&&E(r(e,"rect"))&&x(e,"targetIsSectionRoot")}function X(e){if(!i(e))return!1;let n=r(e,"placement"),t=r(e,"boundary");return o(e,"anchorBlockId")&&m(r(e,"anchorRef"))&&(n==="before"||n==="after")&&i(t)&&c(t,"top")&&c(t,"left")&&c(t,"width")}function E(e){return i(e)&&["top","left","width","height"].every(n=>c(e,n))}function K(e){if(!i(e))return!1;let n=r(e,"rect"),t=r(e,"layout"),s=i(t)?r(t,"containingBlock"):null,p=r(e,"scrollContext"),g=i(s)&&(a(s,"kind","viewport")&&Reflect.ownKeys(s).length===1||a(s,"kind","document")&&Reflect.ownKeys(s).length===1||a(s,"kind","element")&&o(s,"runtimeNodeId"));return a(e,"version",q)&&o(e,"runtimeNodeId")&&i(n)&&E(r(n,"viewport"))&&E(r(n,"document"))&&i(t)&&o(t,"position")&&o(t,"transform")&&g&&i(p)&&["scrollX","scrollY","viewportWidth","viewportHeight"].every(I=>c(p,I))&&f(p,"scrollContainers")&&Y(r(p,"scrollContainers"))}function Y(e){return Array.isArray(e)&&e.every(n=>i(n)&&o(n,"runtimeNodeId")&&c(n,"scrollLeft")&&c(n,"scrollTop"))}function A(e){return i(e)&&(d(e,"layoutSnapshot")||K(r(e,"layoutSnapshot")))}function k(e){return i(e)&&m(r(e,"ref"))&&f(e,"layoutSnapshot")&&K(r(e,"layoutSnapshot"))&&(d(e,"childBoxes")||Q(r(e,"childBoxes")))&&(d(e,"childRects")||J(r(e,"childRects")))&&(d(e,"layout")||Z(r(e,"layout")))&&(d(e,"spacing")||$(r(e,"spacing")))}function Z(e){if(!i(e))return!1;let n=r(e,"indicatorOrientation");return o(e,"display")&&(n==="horizontal"||n==="vertical")&&l(e,"flexDirection")&&l(e,"gridAutoFlow")}function J(e){return Array.isArray(e)&&e.every(n=>E(n))}function Q(e){return Array.isArray(e)&&e.every(n=>i(n)&&E(r(n,"rect"))&&L(r(n,"margin")))}function L(e){return i(e)&&["marginTop","marginRight","marginBottom","marginLeft"].every(n=>c(e,n))}function $(e){return L(e)&&["paddingTop","paddingRight","paddingBottom","paddingLeft","borderTopWidth","borderRightWidth","borderBottomWidth","borderLeftWidth","columnGap","rowGap"].every(n=>c(e,n))}function v(e){if(!Array.isArray(e))return!1;for(let n=0;n<e.length;n+=1){let t=Object.getOwnPropertyDescriptor(e,String(n));if(t===void 0||!("value"in t)||!k(t.value))return!1}return!0}function ee(e){return i(e)&&Reflect.ownKeys(e).every(n=>typeof n=="string"&&f(e,n)&&(typeof r(e,n)=="string"||r(e,n)===null))}function W(e){return e==null||typeof e=="string"||typeof e=="number"&&Number.isFinite(e)}function te(e){return i(e)&&Reflect.ownKeys(e).every(n=>typeof n=="string"&&f(e,n)&&W(r(e,n)))}function ne(e){if(!i(e))return!1;let n=r(e,"priority");return o(e,"property")&&f(e,"value")&&W(r(e,"value"))&&(!h(e,"priority")||n===void 0||n==="important")}function re(e){return i(e)?(d(e,"attributes")||ee(r(e,"attributes")))&&l(e,"className")&&(d(e,"style")||te(r(e,"style")))&&(d(e,"styleDeclarations")||Array.isArray(r(e,"styleDeclarations"))&&r(e,"styleDeclarations").every(ne)):!1}function ie(e){return i(e)&&c(e,"x")&&c(e,"y")&&(d(e,"detailLevel")||a(e,"detailLevel","summary")||a(e,"detailLevel","full"))}function oe(e){return i(e)&&m(r(e,"ref"))}function se(e){if(!i(e)||!i(r(e,"variables")))return!1;let n=r(e,"variables");return Reflect.ownKeys(n).every(t=>typeof t=="string"&&o(n,t))?d(e,"stylesheets")||O(r(e,"stylesheets")):!1}function ce(e){if(!a(e,"type","request")||!o(e,"id")||!o(e,"kind")||!f(e,"payload"))return!1;let n=r(e,"kind"),t=r(e,"payload");switch(n){case"hit-test-at-point":case"start-text-edit-at-point":return ie(t);case"bridge-get-source-tree":return i(t)&&y(r(t,"composition"))&&u(t,["composition"]);case"get-scroll-metrics":case"clear-theme-override":return j(t);case"bridge-get-history-status":case"bridge-undo":case"bridge-redo":return i(t)&&y(r(t,"composition"))&&u(t,["composition"]);case"bridge-get-source-file":return i(t)&&o(t,"path")&&y(r(t,"composition"))&&u(t,["path","composition"]);case"bridge-resolve-source-location":case"bridge-get-object-edit-context":case"bridge-get-class-name-source":return i(t)&&o(t,"key")&&y(r(t,"composition"))&&u(t,["key","composition"]);case"scroll-to":return i(t)&&c(t,"x")&&c(t,"y");case"scroll-by":return i(t)&&c(t,"deltaX")&&c(t,"deltaY");case"set-interaction-mode":return i(t)&&x(t,"enabled");case"set-selection-visual":return i(t)&&a(t,"version",N)&&m(r(t,"ref"))&&a(t,"visible",!0);case"clear-selection-visual":return i(t)&&a(t,"version",N);case"set-resize-visual":return i(t)&&a(t,"version",T)&&m(r(t,"ref"))&&a(t,"visible",!0);case"clear-resize-visual":return i(t)&&a(t,"version",T);case"set-theme-override":return se(t);case"get-theme-variables":return i(t)&&O(r(t,"names"));case"compute-drop-target-at-point":return i(t)&&c(t,"x")&&c(t,"y")&&(a(t,"dragKind","insert")||a(t,"dragKind","move"))&&(d(t,"movingRef")||m(r(t,"movingRef")));case"observe-node-bounds":case"clear-node-bounds-observer":return i(t)&&(d(t,"ref")||m(r(t,"ref")));case"apply-node-patch":return i(t)&&m(r(t,"ref"))&&re(r(t,"patch"))&&(d(t,"preview")||i(r(t,"preview"))&&o(r(t,"preview"),"sessionId")&&w(r(t,"preview"),"revision")&&h(r(t,"preview"),"revision"));case"get-hit-by-ref":case"get-path-by-ref":case"restore-text-edit":case"clear-text-edit-rollback":return oe(t);case"bridge-initialize-session":case"bridge-get-style-context":return i(t)&&y(r(t,"composition"))&&u(t,["composition"]);case"bridge-get-document":case"bridge-ensure-document-version":case"bridge-acknowledge-document-version":return i(t)&&y(r(t,"composition"))&&b(t,"minVersion")&&b(t,"version")&&u(t,["composition","minVersion","version"]);case"bridge-execute":{if(!i(t))return!1;let s=r(t,"request"),p=r(t,"composition"),g=i(s)?r(s,"composition"):null;return!y(p)||!i(s)||!y(g)?!1:S({routeId:p.routeId,...p.templateId?{effectiveTemplateId:p.templateId}:{}})===S({routeId:g.routeId,...g.templateId?{effectiveTemplateId:g.templateId}:{}})&&u(t,["composition","request"])}case"bridge-subscribe":case"bridge-unsubscribe":return i(t)&&o(t,"subscriptionId")&&y(r(t,"composition"))&&u(t,["subscriptionId","composition"]);default:return!1}}function ae(e){return a(e,"type","response")&&o(e,"id")&&x(e,"ok")&&(d(e,"error")||o(e,"error"))}function de(e){if(!i(e))return!1;let n=r(e,"type");if(typeof n!="string"||!R(r(e,"composition"))||!o(e,"siteId")||!o(e,"at"))return!1;switch(n){case"site-edit.document.changed":return o(e,"snapshotId")&&c(e,"version");case"site-edit.operation.planned":return o(e,"operationId")&&o(e,"baseSnapshotId")&&O(r(e,"changedFiles"));case"site-edit.operation.completed":return i(r(e,"result"));case"site-edit.operation.failed":return o(e,"requestId")&&i(r(e,"error"));case"site-edit.capability.changed":return O(r(e,"keys"));case"site-edit.graph.invalidated":return!0;case"site-edit.graph.ready":return c(e,"version");case"site-edit.graph.error":return o(e,"message");default:return!1}}var pe=new Set(["pointer-down","pointer-move","pointer-leave","pointer-up","pointer-cancel","pointer-click","pointer-double-click"]),B=new Set(["e","s","se"]);function fe(e,n){if(d(e,"resizeSession"))return!0;let t=r(e,"resizeSession");if(!i(t))return!1;let s=r(e,"pointerId"),p=r(t,"pointerId"),g=r(t,"phase"),I=r(t,"edge"),G=n==="pointer-down"?"start":n==="pointer-up"?"commit":n==="pointer-cancel"?"cancel":null;return r(t,"version")===1&&g===G&&o(t,"sessionId")&&String(r(t,"sessionId")).length>0&&typeof s=="number"&&Number.isInteger(s)&&typeof p=="number"&&Number.isInteger(p)&&s===p&&typeof I=="string"&&B.has(I)&&r(e,"resizeEdge")===I&&m(r(t,"ref"))&&["startWidth","startHeight","width","height"].every(z=>c(t,z))}function ue(e){if(!a(e,"type","event")||!o(e,"kind")||!i(r(e,"payload")))return!1;let n=r(e,"kind"),t=r(e,"payload");switch(n){case"text-edit-commit":case"text-edit-cancel":case"text-edit-exit":case"text-edit-input":return m(r(t,"ref"))&&l(t,"value")&&(d(t,"hit")||A(r(t,"hit")));case"node-bounds-change":return A(r(t,"hit"));case"geometry-batch":{let s=r(t,"reason");return U(t,"sequence")&&c(t,"sourceEventAt")&&c(t,"captureStartedAt")&&c(t,"capturedAt")&&(s==="scroll"||s==="resize"||s==="mutation")&&v(r(t,"snapshots"))}case"bridge-event":{let s=r(t,"event"),p=r(t,"composition");return!de(s)||!R(p)?!1:o(t,"subscriptionId")&&S(p)===S(s.composition)}case"route-ready":return R(r(t,"composition"))&&o(t,"editEngineVersion")&&c(t,"sequence")&&c(t,"version");case"bridge-status":{let s=r(t,"state");return(s==="connecting"||s==="ready"||s==="reconnecting"||s==="failed"||s==="reload-required")&&R(r(t,"composition"))&&c(t,"sequence")&&b(t,"attempt")&&b(t,"retryInMs")&&l(t,"messageKey")}case"scroll":{let s=r(t,"metrics");return i(s)&&["scrollX","scrollY","scrollWidth","scrollHeight","viewportWidth","viewportHeight"].every(p=>c(s,p))}default:return pe.has(n)&&c(t,"clientX")&&c(t,"clientY")&&b(t,"buttons")&&b(t,"pointerId")&&(d(t,"hoverVisualOwned")||x(t,"hoverVisualOwned"))&&(d(t,"resizeEdge")||o(t,"resizeEdge")&&B.has(r(t,"resizeEdge")))&&fe(t,n)&&(r(t,"hit")===null||A(r(t,"hit")))&&(d(t,"section")||r(t,"section")===null||H(r(t,"section")))&&(d(t,"sectionGap")||r(t,"sectionGap")===null||X(r(t,"sectionGap")))}}function me(e){if(!i(e))return!1;switch(r(e,"type")){case"request":return ce(e);case"response":return ae(e);case"event":return ue(e);default:return!1}}export{M as SITE_EDIT_FRAME_ANNOUNCE_CHANNEL,P as SITE_EDIT_FRAME_RUNTIME_CHANNEL,q as SITE_EDIT_FRAME_RUNTIME_LAYOUT_SNAPSHOT_VERSION,T as SITE_EDIT_FRAME_RUNTIME_RESIZE_VISUAL_VERSION,N as SITE_EDIT_FRAME_RUNTIME_SELECTION_VISUAL_VERSION,le as SITE_EDIT_FRAME_SECTION_GAP_RADIUS_PX,_ as SITE_EDIT_WINDOW_MESSAGE_NAMESPACE,F as VCP_WINDOW_MESSAGE_SOURCE,C as VCP_WINDOW_MESSAGE_VERSION,be as createSiteEditFrameAnnounceMessage,he as createSiteEditFrameRuntimeMessage,V as createVcpWindowMessageEnvelope,Ie as isSiteEditFrameAnnounceMessage,K as isSiteEditFrameRuntimeLayoutSnapshot,Se as isSiteEditFrameRuntimeMessage,D as isVcpWindowMessageEnvelope};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcp-dev/site-edit-bridge",
3
- "version": "0.8.5",
3
+ "version": "0.9.1",
4
4
  "type": "module",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -74,8 +74,8 @@
74
74
  "typecheck": "tsc -p tsconfig.json --noEmit"
75
75
  },
76
76
  "dependencies": {
77
- "@vcp-dev/contracts": "0.8.5",
78
- "@vcp-dev/site-edit-engine": "0.8.5",
77
+ "@vcp-dev/contracts": "0.9.1",
78
+ "@vcp-dev/site-edit-engine": "0.9.1",
79
79
  "@types/ws": "^8.18.1",
80
80
  "ws": "^8.20.1"
81
81
  },