@vcp-dev/site-edit-bridge 0.8.0 → 0.8.2

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 oe from"node:http";import{existsSync as E,readFileSync as R}from"node:fs";import{randomUUID as Tt}from"node:crypto";import{createRequire as Pe}from"node:module";import{Socket as Ee}from"node:net";import _ from"node:path";import{basename as Oe,dirname as T,join as P}from"node:path";import{fileURLToPath as Be}from"node:url";import Ye from"node:http";import Y from"node:fs";import{createHash as Ie,randomBytes as Ze,timingSafeEqual as Xe}from"node:crypto";import I from"node:path";import{WebSocket as we,WebSocketServer as et}from"ws";import{createPreviewSiteEditEngineRuntime as tt,openFileHistoryStore as nt,resolveManagedPageTemplateComposition as it,scanSiteEditCompositionsFromFiles as ot}from"@vcp-dev/site-edit-engine";import{resolveNextAppRouteId as st,scanNextAppRouterRoutesFromFiles as rt}from"@vcp-dev/site-edit-engine/next-app-router";import{SiteEditSourceWatcher as at}from"@vcp-dev/site-edit-engine/source-watcher";function de(e){let t=new Map,n=[],i=new Map,s=[],o=e.pageComposition.status==="supported"?e.pageComposition.placementUnitKeys:[],r=new Map(o.map((d,h)=>[d,h])),c=e.pageComposition.status==="supported"?{status:"supported",containerKey:e.pageComposition.containerKey,hasBusinessMembers:e.pageComposition.hasBusinessMembers,placementUnitKeys:e.pageComposition.placementUnitKeys,placements:e.pageComposition.placements.map(d=>({placementKey:d.placementKey,placementUnitKey:d.placementUnitKey,relation:d.relation}))}:{status:"unsupported",reason:e.pageComposition.reason,diagnostics:e.pageComposition.diagnostics},a=e.entries.flatMap((d,h)=>d.dynamicDataSummary?[[h,d.dynamicDataSummary]]:[]),u=d=>{let h=t.get(d);if(typeof h=="number")return h;let f=n.length;return n.push(d),t.set(d,f),f},l=d=>{let h=null;for(let f of qe(d)){let O=`${h??"root"}\0${f}`,v=i.get(O);if(typeof v=="number"){h=v;continue}let y=s.length;s.push([h,u(f)]),i.set(O,y),h=y}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:c,tokens:n,nodes:s,entries:e.entries.map(d=>{let h=d.pageCompositionUnitKey?r.get(d.pageCompositionUnitKey)??-1:-1;if(d.pageCompositionUnitKey&&h<0)throw new Error(`Render entry ${d.key} references unknown page composition unit ${d.pageCompositionUnitKey}`);return[l(d.key),Ve(d.operationSummary),...h>=0?[h]:[]]}),...a.length>0?{dynamicDataSummaries:a}:{}}}function Ve(e){return(e.canUpdateText?1:0)|(e.canInsertChild?2:0)|(e.canMove?4:0)|(e.canRemove?8:0)}function qe(e){if(!e)return[];let t=[],n=0,i=ue(e,n);if(i<0)return t.push(e),t;for(t.push(e.slice(0,i)),n=i;n<e.length;){if(i=ue(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 ue(e,t){let n=e.indexOf("/",t),i=e.indexOf("::",t);return n<0?i:i<0?n:Math.min(n,i)}var he="SITE_EDIT_COMPOSITION_SESSION_MISMATCH",Q="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(p(t)&&p(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!p(t)||typeof t.type!="string"?!1:t.type==="request"?We(t.payload,n):t.type==="response"||t.type==="error"?p(t.payload)&&typeof t.payload.id=="string":t.type==="event"?p(t.payload)&&p(t.payload.event):t.type==="auth"?p(t.payload)&&typeof t.payload.key=="string":t.type==="auth-ok"&&p(t.payload)&&t.payload.ok===!0}},M=class{constructor(t){this.options=t,this.session={subscribedCompositionKeys:new Set},this.messageQueue=new G,this.eventDispatcher=new J(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=W(i),r=await this.resolve(o),c=await this.options.engine.initializeSession({composition:r.context,...i.mutationContext?{mutationContext:i.mutationContext}:{}});this.activateSession(r.context),this.sendJson({type:"response",payload:{id:s,kind:i.kind,result:S({...c,data:{...c.data,document:le(c.data.document)}},r.context)}});return}case"get-document":{let o=await this.resolveWireContext(i),r=await this.options.engine.getDocument(o);this.sendResult(s,i.kind,Ge(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,S(r,o));return}case"get-style-context":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,S(await this.options.engine.getStyleContext(o),o));return}case"get-object-edit-context":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,S(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,S(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,S(await this.options.engine.getSourceTree(o),o));return}case"get-source-file":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,S(await this.options.engine.getSourceFile({path:i.path,composition:o}),o));return}case"resolve-source-location":{let o=await this.resolveWireContext(i),r=S(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(w(o)!==w(r))throw new x(he,"The execute request composition does not match its operation composition.");let c=await this.normalizeOperationRequest(i.request,o);await this.handleBufferedOperation(s,i.kind,()=>this.options.engine.execute(c));return}case"undo":case"redo":{let o=await this.resolveWireContext(i);await this.handleBufferedOperation(s,i.kind,()=>i.kind==="undo"?this.options.engine.undo(o):this.options.engine.redo(o));return}}}catch(n){let i=m.extractRequestInfo(t);this.sendJson({type:"error",payload:{...i,message:z(n),code:$(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 x(Q,"Initialize a composition session before issuing this request.");if(w(i)!==w(n.context))throw new x(he,"The request composition does not match the active socket session.");return n.context}async resolveWireContext(t){let n=W(t);return this.resolveAndAssert(n)}async resolveOperationWireContext(t){let n=ze(t);return this.resolveAndAssert(n)}activateSession(t){this.session.activeComposition=t,this.session.subscribedCompositionKeys.clear(),this.session.subscribedCompositionKeys.add(w(t))}async normalizeOperationRequest(t,n){let i={...t,composition:pe(n)};if(i.target.kind==="route"){let s=i.target,o=W(s),r=await this.resolveAndAssert(o);i.target={...s,composition:pe(r)}}return i}handleEngineEvent(t){let n=t?.composition;if(!$e(n))return;let i=w(n);this.session.subscribedCompositionKeys.has(i)&&(this.eventDispatcher.push(t),t.type==="site-edit.graph.invalidated"&&i===Je(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=Qe(t);this.sendJson({type:"error",payload:{...i,message:z(n),code:$(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:z(s),code:$(s)}})}finally{this.eventDispatcher.flush()}}},x=class extends Error{constructor(t,n){super(n),this.code=t,this.name="BridgeProtocolError"}},J=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))}},G=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 We(e,t){if(!p(e)||typeof e.id!="string"||!m.isRequestKind(e.kind))return!1;let n=k(e.composition);switch(e.kind){case"initialize-session":return n&&(e.mutationContext===void 0||L(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&&Le(e.request)&&(e.request.mutationContext===void 0||L(e.request.mutationContext))&&(t.validateOperationRequest?.(e.request)??!0);case"undo":case"redo":return n&&e.mutationContext===void 0||n&&L(e.mutationContext)}}function Le(e){return p(e)&&typeof e.id=="string"&&typeof e.siteId=="string"&&typeof e.baseSnapshotId=="string"&&k(e.composition)&&typeof e.kind=="string"&&p(e.target)&&(e.target.kind!=="route"||k(e.target.composition))&&typeof e.documentVersion=="number"&&Number.isInteger(e.documentVersion)&&e.documentVersion>=0&&p(e.params)}function k(e){return p(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 $e(e){return p(e)&&typeof e.routeId=="string"&&(e.effectiveTemplateId===void 0||typeof e.effectiveTemplateId=="string")}function W(e){if(k(e.composition))return e.composition;throw new x(Q,"A composition selector is required for this request.")}function ze(e){if(p(e)&&k(e.composition))return e.composition;throw new x(Q,"A composition selector is required for execute.")}function pe(e){return{routeId:e.routeId,...e.effectiveTemplateId?{templateId:e.effectiveTemplateId}:{}}}function Je(e){return e.activeComposition?w(e.activeComposition):null}function w(e){return JSON.stringify([e.routeId,e.effectiveTemplateId??null])}function S(e,t){return p(e)&&e.ok===!0?{...e,composition:t}:e}function Ge(e,t){return!p(e)||e.ok!==!0?e:{...e,...t?{composition:t}:{},data:le(e.data)}}function le(e){let t=e;return de(t.routeId?t:{...t,routeId:t.composition.routeId})}function p(e){return typeof e=="object"&&e!==null}function L(e){return p(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 $(e){if(!(!p(e)||typeof e.code!="string"||e.code.length===0))return e.code}function z(e){return e instanceof Error||p(e)&&typeof e.message=="string"&&e.message.length>0?e.message:"Unknown websocket operation failure"}function Qe(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 ct,computeSiteEditCompositionKey as C}from"@vcp-dev/contracts";var ut="127.0.0.1",dt=30218,ht="/__vcp/site-edit/bridge",xe=6*1024*1024,pt=xe*2,lt=3e3,fe=50,me="__VCP_SITE_EDIT_BRIDGE_SERVERS__";function Ce(e,t,n={}){let i=new ee(ft(t),e,!1,n);return i.start({listen:!1}),i}var ee=class{constructor(t,n=Ye.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=xt({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 at({projectRoot:this.options.projectRoot,watch_dirs:mt(this.options.runtime.watch_dirs),interval_ms:this.options.runtime.watch_interval_ms,debounce_ms:this.options.runtime.watch_debounce_ms??fe,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=It(),n=wt(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??tt)({...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=yt(t.composition),s=this.getRuntime(),o=g(i);await s.initializeComposition(o);let c=s.getDocument(o).data;await this.recordRuntimeVersion(c.version,i);let a=(await s.getHistoryStatus()).data;return{ok:!0,composition:i,data:{document:c,historyStatus:a}}}),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 Z(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 Z(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 Z(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??nt)(St({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=C(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?C(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??fe;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=gt(this.options.projectRoot),i=rt(n),s=i.length>0?i:(this.options.runtime.routes??[]).map(a=>({...a})),o=ot({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(a=>[C(a.context),a])),c=new Map(o.map(a=>[C(a.context),a]));if(this.runtime){for(let[a,u]of r){let l=c.get(a);(!l||l.entryFile!==u.entryFile)&&this.runtime.unregisterComposition(g(u.context))}for(let[a,u]of c){let l=r.get(a);(!l||l.entryFile!==u.entryFile)&&this.runtime.registerComposition(u.context,u.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=st(t.routeId,this.routes,this.options.basePath);if(!n)throw new Error(`Route is not indexed by the preview bridge: ${t.routeId}`);let i=this.routes.find(r=>r.routeId===n);if(!i)throw new Error(`Route is not indexed by the preview bridge: ${t.routeId}`);let s=it({selector:{routeId:n,...t.templateId?{templateId:t.templateId}:{}},files:this.compositionFiles,canonicalEntryFile:i.entryFile}),o=C(s.context);if(!this.compositions.some(r=>C(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(C(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 ft(e){return{tenantId:e.tenantId,siteId:e.siteId,snapshotId:e.snapshotId,projectRoot:I.resolve(e.projectRoot??process.cwd()),basePath:e.basePath??"",host:e.host??ut,port:e.port??dt,path:e.path??ht,sessionKey:e.sessionKey??_t(),historyRoot:e.historyRoot,allowedOrigins:e.allowedOrigins??[],runtime:e.runtime??{}}}function mt(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 gt(e){let t=[],n=["app","src/app",".vcp"],i=new Set([".git",".next",".turbo","coverage","dist","node_modules","output","snapshot-store"]),s=o=>{if(!Y.existsSync(o))return;let r;try{r=Y.readdirSync(o,{withFileTypes:!0})}catch{return}for(let c of r){if(c.name.startsWith(".")&&c.name!==".vcp")continue;if(c.isDirectory()){if(i.has(c.name))continue;s(I.join(o,c.name));continue}if(!c.isFile())continue;let a=I.join(o,c.name),u="";try{u=Y.readFileSync(a,"utf8")}catch{}t.push({path:I.relative(e,a).replaceAll(I.sep,"/"),content:u})}};for(let o of n)s(I.join(e,o));return t.sort((o,r)=>o.path.localeCompare(r.path))}function yt(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 St(e){return I.join(I.resolve(e.root),ge(e.siteId),ge(e.snapshotId),Ie("sha256").update(e.editingSessionId).digest("hex").slice(0,32))}function ge(e){return/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(e)&&e!=="."&&e!==".."?e:Ie("sha256").update(e).digest("hex").slice(0,32)}function It(){let e=globalThis;return e[me]??=new Map,e[me]}function wt(e){return`${e.projectRoot}:${e.host}:${e.port}:${e.path}:${e.historyRoot??""}`}function Z(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 xt(e){let t=new et({maxPayload:xe,noServer:!0}),n=new WeakSet,i=o=>{new M({socket:new te(o),engine:e.engine,validateOperationRequest:r=>ct.safeParse(r).success})},s=(o,r,c)=>{if(!Ct(o,e))return;let a=bt(o,e);if(!a){r.write(`HTTP/1.1 401 Unauthorized\r
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
2
2
  Connection: close\r
3
3
  \r
4
- `),r.destroy();return}a.authenticatedByHeader&&n.add(o),t.handleUpgrade(o,r,c,u=>{t.emit("connection",u,o)})};return e.server.on("upgrade",s),t.on("connection",(o,r)=>{if(n.has(r)){i(o);return}Rt(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 te=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===we.OPEN){if(this.socket.bufferedAmount+Buffer.byteLength(t,"utf8")>pt){this.socket.close(1013,"bridge backpressure");return}this.socket.send(t)}}close(t,n){this.socket.close(t,n)}};function Ct(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=X(e.headers["x-vcp-site-edit-key"]),s=be(i,t.sessionKey),o=X(e.headers.host),r=X(e.headers.origin);return o&&!Et(o,t.host,r)?null:r?kt(r,o,t.allowedOrigins)?{authenticatedByHeader:s}:null:s?{authenticatedByHeader:!0}:null}function Rt(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=c=>{try{let a=m.parseMessage(c.toString());if(a.type!=="auth"||!be(a.payload.key,t)){r();return}o(),e.readyState===we.OPEN&&e.send(m.stringifyMessage({type:"auth-ok",payload:{ok:!0}})),n()}catch{r()}},e.on("message",s),e.on("close",o)}function be(e,t){if(!e)return!1;let n=Buffer.from(e),i=Buffer.from(t);return n.length===i.length&&Xe(n,i)}function Et(e,t,n){let i=Se(e),s=Se(t);return i===s||ye(s)&&ye(i)&&(!n||ne(n,e))||vt(s)&&(!n||ne(n,e))}function vt(e){return e==="0.0.0.0"||e==="::"}function ye(e){return e==="localhost"||e==="127.0.0.1"||e==="::1"}function kt(e,t,n){return n.includes(e)||(t?ne(e,t):!1)}function ne(e,t){try{return new URL(e).host===Re(t)}catch{return!1}}function Se(e){let t=Re(e);return t.startsWith("[")?t.slice(1,t.indexOf("]")):t.split(":").length-1===1?t.split(":",1)[0]??"":t}function Re(e){return e.trim().toLowerCase()}function X(e){return Array.isArray(e)?e[0]:e}function _t(){return Ze(32).toString("base64url")}var Pt="next",He="127.0.0.1",Ot=3e3,F="/__vcp/site-edit/bridge",Ae="/__vcp/site-edit/health",Bt="probe",Ht="render",ve="/_error",U="/__vcp/site-edit/client/",At=`${U}auto-bootstrap.js`,De='data-vcp-site-edit-bootstrap="true"',Dt=["next.config.ts","next.config.mts","next.config.cts","next.config.js","next.config.mjs","next.config.cjs"],Mt="@vcp-dev/site-edit-engine/webpack-loader",Nt=/@vcp\/site-edit-engine\/(?:webpack-loader|site-edit-instrumentation-loader)/,jt=[/\bconfig\.webpack\s*=/,/\bwebpack\s*\([^)]*\)\s*\{/,/\bwebpack\s*:\s*(?:async\s*)?(?:\([^)]*\)|[A-Za-z_$][\w$]*)?\s*=>/,/\bwebpack\s*:\s*(?:async\s+)?function\b/],Ft=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??oe.createServer,s=t.attachBridgeServer??Ce,o=t.loadNext??yn,r=_.resolve(e.projectRoot??process.cwd()),c=e.host??He,a=e.port??xn(n.env.PORT)??Ot,u=e.bridgePath??F,l=$t(u),d=pn(),h=e.basePath??n.env.VCP_SITE_PREVIEW_BASE_PATH??"/",f=(e.tenantId??n.env.VCP_TENANT_ID)?.trim()||void 0,O=await o(r),v=Ut(r),y=O({dev:!0,dir:r,hostname:c,port:a,...Kt(v)}),je=y.getRequestHandler(),Fe=e.siteId??n.env.VCP_SITE_ID??"018f6f4d-a9b8-7120-8000-000000000120",re=e.snapshotId??n.env.VCP_SNAPSHOT_ID??wn(r),ae=e.historyRoot??n.env.VCP_SITE_EDIT_HISTORY_ROOT,ce=ae?.trim()?_.resolve(ae):void 0,B=null,Ue={launchId:Tt(),pid:process.pid,snapshotId:re},b=i((q,D)=>{Xt({basePath:h,bridgePath:u,bridgeHealthPath:l,bridgeSessionKey:d,getBridgeHealth:()=>B?.getHealth()??sn(u),launch:Ue,runRenderProbe:()=>tn(y),handle:je,request:q,response:D}).catch(Ke=>{console.error(Ke),D.headersSent||(D.statusCode=500),D.end("site edit preview request failed")})}),K=null,H=null,V=()=>H||(j(()=>n.off("SIGINT",A)),j(()=>n.off("SIGTERM",A)),j(()=>K?.()),K=null,j(()=>B?.stop()),B=null,H=Promise.allSettled([bn(b),Rn(()=>y.close())]).then(()=>{}),H),A=()=>{V()};try{return await y.prepare(),B=s(b,{...f?{tenantId:f}:{},siteId:Fe,snapshotId:re,projectRoot:r,basePath:h,host:c,port:a,path:u,sessionKey:d,...ce?{historyRoot:ce}:{}}),K=Wt({server:b,bridgePath:u,handleUpgrade:y.getUpgradeHandler()}),n.on("SIGINT",A),n.on("SIGTERM",A),await Cn(b,a,c),{bundler:v,close:V,host:c,port:En(b,a),server:b}}catch(q){throw await V(),q}}function Ut(e){let t=Vt(e);return t&&qt(t)?"webpack":"turbopack"}function Kt(e){return e==="webpack"?{webpack:!0}:{turbopack:!0}}function Vt(e){for(let t of Dt){let n=P(e,t);if(E(n))return R(n,"utf8")}return null}function qt(e){return e.includes(Mt)?!0:Nt.test(e)&&jt.some(t=>t.test(e))}function Wt(e){let t=(n,i,s)=>{Lt(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 Lt(e,t){return new URL(e??"/","http://localhost").pathname===t}function $t(e=F){if(e===F)return Ae;let t=(e.startsWith("/")?e:`/${e}`).replace(/\/+$/,"");return t.endsWith("/bridge")?`${t.slice(0,-7)}/health`:t?`${t}/health`:"/health"}function zt(e){let t=JSON.stringify({basePath:e.basePath,wsPath:e.bridgePath,bridge_session_key:e.bridgeSessionKey,defer_initial_sync:!0,runtime_versions:e.runtimeVersions??Jt()});return`<script type="module" ${De}>import { startSiteEditAutoBootstrap } from ${JSON.stringify(At)};void startSiteEditAutoBootstrap(window, ${t}).catch(() => undefined);</script>`}function Jt(){return{bridge:ie("@vcp-dev/site-edit-bridge"),contracts:ie("@vcp-dev/contracts"),engine:ie("@vcp-dev/site-edit-engine")}}function ie(e){let t=Pe(import.meta.url);try{let n=t.resolve(e),i=Gt(n,e);if(!i)return;let s=JSON.parse(R(i,"utf8"));return typeof s.version=="string"?s.version:void 0}catch{return}}function Gt(e,t){let n=_.parse(e).root,i=T(e);for(;i&&i!==n;){let s=P(i,"package.json");if(E(s))try{if(JSON.parse(R(s,"utf8")).name===t)return s}catch{return}i=T(i)}}function Qt(e,t){if(e.includes(De))return e;let n=zt(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=T(Be(import.meta.url)),n=E){return Me(e,t,n)?.path??null}function Me(e,t=T(Be(import.meta.url)),n=E){let i=new URL(e??"/","http://localhost").pathname;if(!i.startsWith(U))return null;let s=i.slice(U.length);if(!Ft.has(s))return null;let o=se(Sn(t),s);if(Oe(t)!=="src")return{path:o,requiresTranspile:!1};let r=se(t,s.replace(/\.js$/,".ts"));return n(r)?{path:r,requiresTranspile:!0}:{path:o,requiresTranspile:!1}}async function Yt(e,t){let n=Me(e.url);if(!n)return!1;if(!E(n.path))return t.writeHead(404),t.end("site edit client asset not found"),!0;let i=n.requiresTranspile?await Zt(R(n.path,"utf8")):R(n.path);return t.writeHead(200,{"cache-control":"no-store","content-type":"text/javascript; charset=utf-8"}),t.end(i),!0}async function Zt(e){let t=await import("typescript");return t.transpileModule(e,{compilerOptions:{module:t.ModuleKind.ES2022,target:t.ScriptTarget.ES2022}}).outputText}async function Xt({basePath:e,bridgePath:t,bridgeHealthPath:n,bridgeSessionKey:i,getBridgeHealth:s,launch:o,runRenderProbe:r,handle:c,request:a,response:u}){if(await on(a,u,n,s,o,r)||await Yt(a,u))return;let l=rn(a),d=an(a),h=l||d?dn(u,{basePath:e,bridgePath:t,bridgeSessionKey:i,patchNextDevChunk:d}):()=>{};try{await c(a,u)}catch(f){throw h(),f}}function en(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 tn(e){let t=new oe.IncomingMessage(new Ee);t.method="GET",t.url=ve,t.headers={host:He};let n=new oe.ServerResponse(t);n.assignSocket(new Ee);try{return await e.renderToHTML(t,n,ve,{}),{verdict:"ok"}}catch(i){return en(i)}finally{try{let i=n.socket;i&&(n.detachSocket(i),i.destroy())}catch{}}}function nn(e){return new URL(e??"/","http://localhost").searchParams.get(Bt)===Ht}async function on(e,t,n,i,s,o){if(e.method!=="GET"||new URL(e.url??"/","http://localhost").pathname!==n)return!1;let c=i(),a=nn(e.url)?await o():void 0,u={...c,launch:s,...a?{render:a}:{}};return t.writeHead(c.ok?200:503,{"cache-control":"no-store","content-type":"application/json; charset=utf-8"}),t.end(JSON.stringify(u)),!0}function sn(e){return{ok:!1,bridgePath:e,runtimeReady:!1,routesIndexed:0,sessionRequired:!0}}function rn(e){return cn(e)?(e.headers["accept-encoding"]="identity",!0):!1}function an(e){return un(e)?(e.headers["accept-encoding"]="identity",!0):!1}function cn(e){if(e.method!=="GET")return!1;let t=new URL(e.url??"/","http://localhost").pathname;if(t.startsWith("/_next/")||t.startsWith(U)||t===F||t===Ae)return!1;let n=e.headers.accept??"";return n===""||n.includes("text/html")}function un(e){if(e.method!=="GET"||!String(e.headers["user-agent"]??"").includes("Firefox"))return!1;let n=new URL(e.url??"/","http://localhost").pathname;return n.startsWith("/_next/static/chunks/")&&n.endsWith(".js")}function dn(e,t){let n=[],i=e,s=i.flushHeaders.bind(e),o=i.write.bind(e),r=i.end.bind(e);return i.flushHeaders=()=>{},i.write=(c,a,u)=>(c!==void 0&&n.push(ke(c,_e(a))),Te(a),Te(u),!0),i.end=(c,a,u)=>{let l=typeof c=="function"?void 0:c;l!==void 0&&n.push(ke(l,_e(a))),i.write=o,i.end=r,i.flushHeaders=s;let d=Buffer.concat(n),h=hn(e,d,t);h!==d&&!e.headersSent&&e.removeHeader("content-length");let f=typeof c=="function"?c:typeof a=="function"?a:typeof u=="function"?u:void 0;return f?r(h,f):r(h)},()=>{i.write=o,i.end=r,i.flushHeaders=s}}function hn(e,t,n){if(ln(e,t))return Buffer.from(Qt(t.toString("utf8"),n));if(n.patchNextDevChunk&&fn(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 ln(e,t){if(e.statusCode<200||e.statusCode>=300)return!1;let n=e.getHeader("content-type"),i=Array.isArray(n)?n.join(";"):String(n??"");return t.toString("utf8",0,256).includes("<html")&&(i===""||i.includes("text/html"))}function fn(e){if(e.statusCode<200||e.statusCode>=300)return!1;let t=e.getHeader("content-type"),n=Array.isArray(t)?t.join(";"):String(t??"");return n===""||n.includes("javascript")||n.includes("ecmascript")}function 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}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(`
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 ke(e,t){return Buffer.isBuffer(e)?e:e instanceof Uint8Array?Buffer.from(e):Buffer.from(String(e),t)}function _e(e){return typeof e=="string"?e:void 0}function Te(e){typeof e=="function"&&e()}async function yn(e){let n=Pe(P(e,"package.json"))(Pt);return n.default??n}function Sn(e){return Oe(e)!=="src"?e:se(In(e),"dist")}function In(e){return Ne(e)?_.posix.dirname(e):T(e)}function se(e,t){return Ne(e)?_.posix.join(e,t):P(e,t)}function Ne(e){return e.includes("/")&&!e.includes("\\")}function wn(e){let t=P(e,".vcp/current-snapshot.json");if(!E(t))return"sandbox_worktree";try{let n=JSON.parse(R(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 bn(e){return new Promise(t=>{e.close(()=>t())})}function j(e){try{e()}catch{}}function Rn(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{Wt as attachNextDevUpgradeHandler,en as classifySiteEditRenderProbeError,zt as createSiteEditAutoBootstrapHtmlSnippet,Qt as injectSiteEditAutoBootstrap,nn as isSiteEditRenderProbeRequested,mn as patchNextFirefoxDevChunk,an as prepareFirefoxNextDevChunkPatchRequest,rn as prepareSiteEditHtmlInjectionRequest,$t as resolveSiteEditBridgeHealthPath,Me as resolveSiteEditClientAsset,Zn as resolveSiteEditClientAssetPath,Ut as resolveSiteEditNextDevBundler,tn as runSiteEditRenderProbe,Yn as startSiteEditNextDevServer,Zt as transpileSiteEditClientSource};
6
+ `)],[["findSourceMapURL: _appfindsourcemapurl.findSourceMapURL,"," debugChannel,"," startTime: 0"].join("\\n"),["unstable_allowPartialStream: true,"," debugChannel,"," startTime: 0"].join("\\n")],["debugChannel: createDebugChannel && createDebugChannel(requestHeaders)","debugChannel: undefined"],["debugChannel: createDebugChannel && createDebugChannel(headers)","debugChannel: undefined"]].reduce((n,[i,s])=>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};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcp-dev/site-edit-bridge",
3
- "version": "0.8.0",
3
+ "version": "0.8.2",
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.0",
78
- "@vcp-dev/site-edit-engine": "0.8.0",
77
+ "@vcp-dev/contracts": "0.8.2",
78
+ "@vcp-dev/site-edit-engine": "0.8.2",
79
79
  "@types/ws": "^8.18.1",
80
80
  "ws": "^8.20.1"
81
81
  },