@vcp-dev/site-edit-bridge 0.10.35 → 0.10.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/engine-worker.js +2 -2
- package/dist/index.js +7 -7
- package/dist/next-dev-server.js +4 -4
- package/dist/server.js +2 -2
- package/package.json +3 -3
package/dist/engine-worker.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{parentPort as tt,workerData as nt}from"node:worker_threads";function H(t){let e=t&&typeof t=="object"?t:null,n=typeof e?.message=="string"&&e.message.length>0?e.message:String(t);return{name:typeof e?.name=="string"?e.name:"Error",message:n,...typeof e?.code=="string"&&e.code.length>0?{code:e.code}:{}}}import oe from"node:http";import _ from"node:fs";import{createHash as J,randomBytes as Re,timingSafeEqual as be}from"node:crypto";import m from"node:path";import{WebSocket as re,WebSocketServer as xe}from"ws";import{createPreviewSiteEditEngineRuntime as ke,openFileHistoryStore as ve,resolveManagedPageTemplateComposition as _e,scanSiteEditCompositionsFromFiles as Te}from"@vcp-dev/site-edit-engine";import{resolveNextAppRouteId as Oe,scanNextAppRouterRoutesFromFiles as Ae}from"@vcp-dev/site-edit-engine/next-app-router";import{SiteEditSourceWatcher as Me}from"@vcp-dev/site-edit-engine/source-watcher";function Y(t){let e=new Map,n=[],i=new Map,o=[],s=t.pageComposition.status==="supported"?t.pageComposition.placementUnitKeys:[],r=new Map(s.map((c,p)=>[c,p])),a=t.pageComposition.status==="supported"?{status:"supported",containerKey:t.pageComposition.containerKey,hasBusinessMembers:t.pageComposition.hasBusinessMembers,placementUnitKeys:t.pageComposition.placementUnitKeys,placements:t.pageComposition.placements.map(c=>({placementKey:c.placementKey,placementUnitKey:c.placementUnitKey,relation:c.relation}))}:{status:"unsupported",reason:t.pageComposition.reason,diagnostics:t.pageComposition.diagnostics},h=t.entries.flatMap((c,p)=>c.dynamicDataSummary?[[p,c.dynamicDataSummary]]:[]),d=new Map(t.entries.map((c,p)=>[c.key,p])),l=[];for(let[c,p]of t.entries.entries()){let g=p.pageCompositionActionScope;if(!g)continue;if(g.kind!=="source-siblings"){l.push([c,{kind:g.kind}]);continue}let O=g.siblingKeys.map(x=>{let k=d.get(x);if(k===void 0)throw new Error("Render entry "+p.key+" references missing source sibling "+x);return k});l.push([c,{kind:"source-siblings",siblingEntryIndexes:O}])}let S=c=>{let p=e.get(c);if(typeof p=="number")return p;let g=n.length;return n.push(c),e.set(c,g),g},Q=c=>{let p=null;for(let g of pe(c)){let O=`${p??"root"}\0${g}`,x=i.get(O);if(typeof x=="number"){p=x;continue}let k=o.length;o.push([p,S(g)]),i.set(O,k),p=k}if(p===null)throw new Error("Document key must not be empty");return p};return{encoding:"segment-trie-v1",siteId:t.siteId,snapshotId:t.snapshotId,composition:{...t.composition},routeId:t.composition.routeId,version:t.version,pageComposition:a,tokens:n,nodes:o,entries:t.entries.map(c=>{let p=c.pageCompositionUnitKey?r.get(c.pageCompositionUnitKey)??-1:-1;if(c.pageCompositionUnitKey&&p<0)throw new Error(`Render entry ${c.key} references unknown page composition unit ${c.pageCompositionUnitKey}`);return[Q(c.key),he(c.operationSummary),...p>=0?[p]:[]]}),...l.length>0?{pageCompositionActionScopes:l}:{},...t.entries.every(c=>c.parentKey!==void 0)?{entryParentNodeIds:t.entries.map(c=>c.parentKey===null?null:Q(c.parentKey))}:{},...h.length>0?{dynamicDataSummaries:h}:{}}}function he(t){return(t.canUpdateText?1:0)|(t.canInsertChild?2:0)|(t.canMove?4:0)|(t.canRemove?8:0)}function pe(t){if(!t)return[];let e=[],n=0,i=G(t,n);if(i<0)return e.push(t),e;for(e.push(t.slice(0,i)),n=i;n<t.length;){if(i=G(t,n+(t.startsWith("::",n)?2:1)),i<0){e.push(t.slice(n));break}e.push(t.slice(n,i)),n=i}return e}function G(t,e){let n=t.indexOf("/",e),i=t.indexOf("::",e);return n<0?i:i<0?n:Math.min(n,i)}var Z="SITE_EDIT_COMPOSITION_SESSION_MISMATCH",P="SITE_EDIT_COMPOSITION_SESSION_REQUIRED";var f=class t{constructor(){}static parseMessage(e,n={}){let i=JSON.parse(e);if(!t.isMessage(i,n))throw new Error("Invalid site edit bridge message");return i}static stringifyMessage(e){return JSON.stringify(e)}static extractRequestInfo(e){if(u(e)&&u(e.payload)){let n=typeof e.payload.id=="string"?e.payload.id:"unknown",i=this.isRequestKind(e.payload.kind)?e.payload.kind:"get-document";return{id:n,kind:i}}return{id:"unknown",kind:"get-document"}}static isRequestKind(e){return e==="initialize-session"||e==="get-document"||e==="get-history-status"||e==="get-style-context"||e==="get-object-edit-context"||e==="get-class-name-source"||e==="get-source-tree"||e==="get-source-file"||e==="resolve-source-location"||e==="execute"||e==="get-operation-result"||e==="undo"||e==="redo"}static isMessage(e,n={}){return!u(e)||typeof e.type!="string"?!1:e.type==="request"?fe(e.payload,n):e.type==="response"||e.type==="error"?u(e.payload)&&typeof e.payload.id=="string":e.type==="event"?u(e.payload)&&u(e.payload.event):e.type==="auth"?u(e.payload)&&typeof e.payload.key=="string":e.type==="ping"||e.type==="pong"?u(e.payload)&&typeof e.payload.id=="string":e.type==="auth-ok"&&u(e.payload)&&e.payload.ok===!0}},A=class{constructor(e){this.options=e,this.session={subscribedCompositionKeys:new Set},this.messageQueue=new B,this.eventDispatcher=new V(n=>{this.sendJson(n)}),this.unsubscribe=e.engine.subscribe(n=>{this.handleEngineEvent(n)}),e.socket.onmessage=n=>{let i=ge(n.data);if(i!==null){this.sendJson({type:"pong",payload:{id:i}});return}try{this.messageQueue.enqueue(()=>this.handleRawMessage(n.data))}catch(o){this.sendJson({type:"error",payload:{id:"unknown",kind:"get-document",message:o instanceof Error?o.message:"Bridge queue overflow"}}),e.socket.close(1013,"bridge busy")}},e.socket.onclose=()=>{this.unsubscribe(),this.session.activeComposition=void 0,this.session.subscribedCompositionKeys.clear()}}async handleMessage(e){try{let n=e;if(n.type!=="request")return;let i=n.payload,{id:o}=i;switch(i.kind){case"initialize-session":{let s=D(i),r=await this.resolve(s),a=await this.options.engine.initializeSession({composition:r.context,...i.mutationContext?{mutationContext:i.mutationContext}:{}});this.activateSession(r.context),this.sendJson({type:"response",payload:{id:o,kind:i.kind,result:I({...a,data:{...a.data,document:ee(a.data.document)}},r.context)}});return}case"get-document":{let s=await this.resolveWireContext(i),r=await this.options.engine.getDocument(s);this.sendResult(o,i.kind,Ce(r,s));return}case"get-history-status":{let s=await this.resolveWireContext(i),r=await this.options.engine.getHistoryStatus(s);this.sendResult(o,i.kind,I(r,s));return}case"get-style-context":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getStyleContext(s),s));return}case"get-object-edit-context":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getObjectEditContext(i.key,s,i.selectionRef),s));return}case"get-class-name-source":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getClassNameSource(i.key,s),s));return}case"get-source-tree":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getSourceTree(s),s));return}case"get-source-file":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getSourceFile({path:i.path,composition:s}),s));return}case"resolve-source-location":{let s=await this.resolveWireContext(i),r=I(await this.options.engine.resolveSourceLocation({key:i.key,composition:s}),s);this.sendResult(o,i.kind,r);return}case"execute":case"get-operation-result":{let s=await this.resolveOperationWireContext(i.request),r=await this.resolveWireContext(i);if(w(s)!==w(r))throw new C(Z,"The execute request composition does not match its operation composition.");let a=await this.normalizeOperationRequest(i.request,s);if(i.kind==="get-operation-result"){this.sendResult(o,i.kind,await this.options.engine.getOperationResult?.(a)??null);return}await this.handleBufferedOperation(o,i.kind,()=>this.options.engine.execute(a));return}case"undo":case"redo":{let s=await this.resolveWireContext(i);await this.handleBufferedOperation(o,i.kind,()=>i.kind==="undo"?this.options.engine.undo(s):this.options.engine.redo(s));return}}}catch(n){let i=f.extractRequestInfo(e);this.sendJson({type:"error",payload:{...i,message:F(n),code:K(n)}})}}async resolve(e){return this.options.engine.resolveComposition(e)}async resolveAndAssert(e){let n=await this.resolve(e),i=this.session.activeComposition;if(!i)throw new C(P,"Initialize a composition session before issuing this request.");if(w(i)!==w(n.context))throw new C(Z,"The request composition does not match the active socket session.");return n.context}async resolveWireContext(e){let n=D(e);return this.resolveAndAssert(n)}async resolveOperationWireContext(e){let n=Se(e);return this.resolveAndAssert(n)}activateSession(e){this.session.activeComposition=e,this.session.subscribedCompositionKeys.clear(),this.session.subscribedCompositionKeys.add(w(e))}async normalizeOperationRequest(e,n){let i={...e,composition:X(n)};if(i.target.kind==="route"){let o=i.target,s=D(o),r=await this.resolveAndAssert(s);i.target={...o,composition:X(r)}}return i}handleEngineEvent(e){let n=e?.composition;if(!Ie(n))return;let i=w(n);this.session.subscribedCompositionKeys.has(i)&&(this.eventDispatcher.push(e),e.type==="site-edit.graph.invalidated"&&i===we(this.session)&&(this.session.activeComposition=void 0,this.session.subscribedCompositionKeys.delete(i)))}sendResult(e,n,i){this.sendJson({type:"response",payload:{id:e,kind:n,result:i}})}async handleRawMessage(e){try{await this.handleMessage(f.parseMessage(e,{validateOperationRequest:this.options.validateOperationRequest}))}catch(n){let i=Ee(e);this.sendJson({type:"error",payload:{...i,message:F(n),code:K(n)}})}}sendJson(e){this.options.socket.send(f.stringifyMessage(e))}async handleBufferedOperation(e,n,i){this.eventDispatcher.beginBuffering();try{let o=await i();this.sendResult(e,n,o)}catch(o){this.sendJson({type:"error",payload:{id:e,kind:n,message:F(o),code:K(o)}})}finally{this.eventDispatcher.flush()}}},le=256;function ge(t){if(t.length>le||!t.includes('"ping"'))return null;try{let e=JSON.parse(t);return u(e)&&e.type==="ping"&&u(e.payload)&&typeof e.payload.id=="string"?e.payload.id:null}catch{return null}}var C=class extends Error{constructor(e,n){super(n),this.code=e,this.name="BridgeProtocolError"}},V=class{constructor(e){this.send=e,this.bufferedEvents=null}push(e){let n={type:"event",payload:{event:e}};if(this.bufferedEvents){this.bufferedEvents.push(n);return}this.send(n)}beginBuffering(){this.bufferedEvents=[]}flush(){let e=this.bufferedEvents??[];this.bufferedEvents=null,e.forEach(n=>this.send(n))}},B=class{constructor(e=64){this.maxQueued=e,this.queue=Promise.resolve(),this.queued=0}enqueue(e){if(this.queued>=this.maxQueued)throw new Error("Bridge request queue is full");this.queued+=1;let n=async()=>{this.queued-=1,await e()},i=this.queue.then(n,n);return this.queue=i.then(()=>{},()=>{}),i}};function fe(t,e){if(!u(t)||typeof t.id!="string"||!f.isRequestKind(t.kind))return!1;let n=v(t.composition);switch(t.kind){case"initialize-session":return n&&(t.mutationContext===void 0||N(t.mutationContext));case"get-document":case"get-style-context":return n;case"get-object-edit-context":return typeof t.key=="string"&&n&&me(t.selectionRef);case"get-class-name-source":case"resolve-source-location":return typeof t.key=="string"&&n;case"get-history-status":return n;case"get-source-tree":return n;case"get-source-file":return typeof t.path=="string"&&n;case"execute":case"get-operation-result":return n&&ye(t.request)&&(t.request.mutationContext===void 0||N(t.request.mutationContext))&&(e.validateOperationRequest?.(t.request)??!0);case"undo":case"redo":return n&&t.mutationContext===void 0||n&&N(t.mutationContext)}}function me(t){if(t===void 0)return!0;if(!u(t)||typeof t.key!="string"||t.key.length===0)return!1;let e=t.instanceIndex,n=t.instanceCount;return e!==void 0&&(typeof e!="number"||!Number.isInteger(e)||e<0)||n!==void 0&&(typeof n!="number"||!Number.isInteger(n)||n<=0)||typeof e=="number"&&typeof n=="number"&&e>=n?!1:Object.keys(t).every(i=>i==="key"||i==="instanceIndex"||i==="instanceCount")}function ye(t){return u(t)&&typeof t.id=="string"&&typeof t.siteId=="string"&&typeof t.baseSnapshotId=="string"&&v(t.composition)&&typeof t.kind=="string"&&u(t.target)&&(t.target.kind!=="route"||v(t.target.composition))&&typeof t.documentVersion=="number"&&Number.isInteger(t.documentVersion)&&t.documentVersion>=0&&u(t.params)}function v(t){return u(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 Ie(t){return u(t)&&typeof t.routeId=="string"&&(t.effectiveTemplateId===void 0||typeof t.effectiveTemplateId=="string")}function D(t){if(v(t.composition))return t.composition;throw new C(P,"A composition selector is required for this request.")}function Se(t){if(u(t)&&v(t.composition))return t.composition;throw new C(P,"A composition selector is required for execute.")}function X(t){return{routeId:t.routeId,...t.effectiveTemplateId?{templateId:t.effectiveTemplateId}:{}}}function we(t){return t.activeComposition?w(t.activeComposition):null}function w(t){return JSON.stringify([t.routeId,t.effectiveTemplateId??null])}function I(t,e){return u(t)&&t.ok===!0?{...t,composition:e}:t}function Ce(t,e){return!u(t)||t.ok!==!0?t:{...t,...e?{composition:e}:{},data:ee(t.data)}}function ee(t){let e=t;return Y(e.routeId?e:{...e,routeId:e.composition.routeId})}function u(t){return typeof t=="object"&&t!==null}function N(t){return u(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 K(t){if(!(!u(t)||typeof t.code!="string"||t.code.length===0))return t.code}function F(t){return t instanceof Error||u(t)&&typeof t.message=="string"&&t.message.length>0?t.message:"Unknown websocket operation failure"}function Ee(t){try{return f.extractRequestInfo(JSON.parse(t))}catch{return{id:"unknown",kind:"get-document"}}}var M=class{constructor(){this.tail=Promise.resolve()}run(e){let n=this.tail.then(e,e);return this.tail=n.then(()=>{},()=>{}),n}};import{SiteEditOperationRequestSchema as He,computeSiteEditCompositionKey as E}from"@vcp-dev/contracts";var De="127.0.0.1",Ne=30218,Ke="/__vcp/site-edit/bridge",ae=6*1024*1024,Fe=ae*2,Ve=3e3,te=50,q=".vcp/current-snapshot.json",ne="__VCP_SITE_EDIT_BRIDGE_SERVERS__";var j=class{constructor(e,n=oe.createServer((s,r)=>{r.writeHead(404),r.end("VCP site edit bridge server")}),i=!0,o={}){this.options=e,this.server=n,this.closeHttpServerOnStop=i,this.dependencies=o,this.runtime=null,this.activeHistorySessionId=null,this.historySessionTransition=Promise.resolve(),this.mutationQueue=new M,this.operationReceipts=new Map,this.eventListeners=new Set,this.routes=[],this.compositions=[],this.compositionFiles=[],this.compositionResolutionError=null,this.launchCandidateEntries=null,this.stopWatching=null,this.stopWebSocketServer=null,this.pendingChangedFiles=new Set,this.fileChangeTimer=null,this.isStarted=!1,this.stopping=!1,this.runtimeVersionFloors=new Map,this.activeHistoryStore=null,this.versionPersistence=Promise.resolve(),this.versionCheckpoints=new WeakMap,this.bridgeEngine=null,this.lastNotifiedHealth=null}start(e={}){if(!this.isStarted){this.stopping=!1;try{_.mkdirSync(m.join(this.options.projectRoot,".vcp"),{recursive:!0})}catch(n){console.warn(`[vcp-site-edit] failed to ensure .vcp directory: ${n instanceof Error?n.message:String(n)}`)}if(this.refreshCompositions(!0),this.isStarted=!0,this.createRuntime(),this.bridgeEngine=this.createBridgeEngine(),e.webSocket!==!1){let n=ze({server:this.server,path:this.options.path,sessionKey:this.options.sessionKey,host:this.options.host,allowedOrigins:this.options.allowedOrigins,engine:this.bridgeEngine});this.stopWebSocketServer=n.stop}this.stopWatching=new Me({projectRoot:this.options.projectRoot,watch_dirs:Pe(this.options.runtime.watch_dirs),interval_ms:this.options.runtime.watch_interval_ms,debounce_ms:this.options.runtime.watch_debounce_ms??te,max_dirs:this.options.runtime.watch_max_dirs,max_files:this.options.runtime.watch_max_files,max_depth:this.options.runtime.watch_max_depth,max_startup_ms:this.options.runtime.watch_max_startup_ms,on_change:n=>this.handleFileChanged(n),on_batch_change:n=>this.handleFilesChanged(n)}).start(),e.listen!==!1&&this.server.listen(this.options.port,this.options.host),this.notifyHealthChanged()}}getEngine(){if(!this.bridgeEngine)throw new Error("VCP site edit preview bridge runtime is not ready");return this.bridgeEngine}getHealth(){let e=!!this.runtime&&!this.compositionResolutionError;return{ok:this.isStarted&&e,bridgePath:this.options.path,runtimeReady:e,routesIndexed:this.routes.length,sessionRequired:!!this.options.sessionKey}}stop(){this.stopping=!0,this.stopWatching?.(),this.stopWatching=null,this.flushChangedFiles(),this.fileChangeTimer&&(clearTimeout(this.fileChangeTimer),this.fileChangeTimer=null),this.stopWebSocketServer?.(),this.stopWebSocketServer=null,this.runtime?.dispose(),this.runtime=null,this.compositions=[],this.compositionFiles=[],this.compositionResolutionError=null,this.closeHttpServerOnStop&&this.server.close();let e=je(),n=$e(this.options);e.get(n)===this&&e.delete(n),this.isStarted=!1,this.notifyHealthChanged()}notifyHealthChanged(){let e=this.options.onHealthChanged;if(!e)return;let n=this.getHealth(),i=JSON.stringify(n);if(i!==this.lastNotifiedHealth){this.lastNotifiedHealth=i;try{e(n)}catch(o){console.warn(`[vcp-site-edit] onHealthChanged callback failed: ${o instanceof Error?o.message:String(o)}`)}}}createRuntime(e,n=null){let i=this.runtime;this.activeHistoryStore=e??null;let o=(this.dependencies.createRuntime??ke)({...this.options.tenantId?{tenantId:this.options.tenantId}:{},siteId:this.options.siteId,snapshotId:this.options.snapshotId,projectRoot:this.options.projectRoot,compositions:this.compositions,onEvent:s=>{"version"in s&&typeof s.version=="number"&&this.recordRuntimeVersion(s.version,"composition"in s?s.composition:void 0);for(let r of this.eventListeners)r(s)},...e?{historyStore:e}:{},...this.getInitialDocumentVersions().length>0?{initialDocumentVersions:this.getInitialDocumentVersions()}:{}});this.runtime=o,this.activeHistorySessionId=n,i?.dispose(),this.notifyHealthChanged()}createBridgeEngine(){return{resolveComposition:e=>this.resolveComposition(e),initializeSession:e=>this.mutationQueue.run(async()=>{let n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)throw new Error(`${n.code}: ${n.message}`);let i=Ue(e.composition),o=this.getRuntime(),s=y(i);await o.initializeComposition(s);let a=o.getDocument(s).data;await this.recordRuntimeVersion(a.version,i);let h=(await o.getHistoryStatus()).data;return{ok:!0,composition:i,data:{document:a,historyStatus:h}}}),getDocument:async e=>{let n=this.getRuntime(),i=y(e);await n.initializeComposition(i);let o=n.getDocument(i);return await this.recordRuntimeVersion(o.data.version,e),{...o,composition:e}},getHistoryStatus:async e=>({...await this.getRuntime().getHistoryStatus(),composition:e}),getStyleContext:async e=>this.getRuntime().getStyleContext(y(e)),getObjectEditContext:async(e,n,i)=>this.getRuntime().getObjectEditContext(e,y(n),i),getClassNameSource:async(e,n)=>this.getRuntime().getClassNameSource(e,y(n)),getSourceTree:async e=>this.getRuntime().getSourceTree(y(e)),getSourceFile:async e=>this.getRuntime().getSourceFile({path:e.path,composition:y(e.composition)}),resolveSourceLocation:async e=>this.getRuntime().resolveSourceLocation({key:e.key,composition:y(e.composition)}),execute:(e,n)=>this.executeWithReceipt(e,()=>this.mutationQueue.run(async()=>{let i=await this.bindHistorySession(this.options.snapshotId);if(!i.ok)return W(i,e);let o=await this.getRuntime().executeOperation(e);return o.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(o.data.resultVersion,o.composition),o})),getOperationResult:e=>{if(e.siteId!==this.options.siteId||e.baseSnapshotId!==this.options.snapshotId)return null;let n=this.operationReceipts.get(this.operationReceiptKey(e));return n?.fingerprint===this.operationFingerprint(e)?n.result:null},undo:e=>this.mutationQueue.run(async()=>{let n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)return W(n,void 0,e);let i=await this.getRuntime().undo();return i.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(i.data.resultVersion,i.composition??e),i.composition?i:{...i,composition:e}}),redo:e=>this.mutationQueue.run(async()=>{let n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)return W(n,void 0,e);let i=await this.getRuntime().redo();return i.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(i.data.resultVersion,i.composition??e),i.composition?i:{...i,composition:e}}),subscribe:e=>(this.eventListeners.add(e),()=>this.eventListeners.delete(e))}}operationReceiptKey(e){return JSON.stringify([e.siteId,e.baseSnapshotId,e.id])}operationFingerprint(e){return J("sha256").update(JSON.stringify(e)).digest("hex")}executeWithReceipt(e,n){if(e.siteId!==this.options.siteId||e.baseSnapshotId!==this.options.snapshotId)return n();let i=this.operationReceiptKey(e),o=this.operationFingerprint(e),s=this.operationReceipts.get(i);if(s)return s.fingerprint!==o?Promise.reject(new Error("Operation ID was reused with a different request.")):s.result;let r={fingerprint:o,result:n(),settled:!1};return this.operationReceipts.set(i,r),r.result.then(()=>{r.settled=!0;for(let[a,h]of this.operationReceipts){if(this.operationReceipts.size<=256)break;h.settled&&this.operationReceipts.delete(a)}},()=>{this.operationReceipts.delete(i)}),r.result}async bindHistorySession(e){if(!this.options.historyRoot)return{ok:!1,code:"RECOVERY_PERSIST_FAILED",message:"Durable edit history is not configured."};if(this.activeHistorySessionId===e)return{ok:!0};let n=this.historySessionTransition.then(async()=>{if(this.activeHistorySessionId===e)return;let i=await(this.dependencies.openHistoryStore??ve)(qe({root:this.options.historyRoot,siteId:this.options.siteId,snapshotId:this.options.snapshotId,editingSessionId:e}));if(!this.isStarted)return;let o=i.readDocumentVersion?await i.readDocumentVersion():0,s=this.versionCheckpoints.get(i);s?s.durableVersion=Math.max(s.durableVersion,o):this.versionCheckpoints.set(i,{durableVersion:o,requestedVersion:o,pending:null});let r=this.compositions[0]?.context;if(r){let a=E(r);this.runtimeVersionFloors.set(a,Math.max(this.runtimeVersionFloors.get(a)??0,o))}this.createRuntime(i,e)});this.historySessionTransition=n.catch(()=>{});try{return await n,{ok:!0}}catch{return{ok:!1,code:"RECOVERY_PERSIST_FAILED",message:"Durable edit history could not be opened."}}}recordRuntimeVersion(e,n){let i=n?E(n):null;i&&this.runtimeVersionFloors.set(i,Math.max(this.runtimeVersionFloors.get(i)??0,e));let o=this.activeHistoryStore;if(!o?.writeDocumentVersion)return Promise.resolve();let s=i?this.runtimeVersionFloors.get(i)??e:e,r=this.versionCheckpoints.get(o);if(r||(r={durableVersion:0,requestedVersion:0,pending:null},this.versionCheckpoints.set(o,r)),s<=r.durableVersion)return Promise.resolve();if(r.requestedVersion=Math.max(r.requestedVersion,s),r.pending)return r.pending;let a=r,h=this.versionPersistence.then(async()=>{try{for(;a.requestedVersion>a.durableVersion;){let d=a.requestedVersion;await o.writeDocumentVersion(d),a.durableVersion=Math.max(a.durableVersion,d)}}catch{console.warn("[vcp-site-edit] document version checkpoint persistence failed")}finally{a.pending=null}});return a.pending=h,this.versionPersistence=h,h}handleFileChanged(e){this.handleFilesChanged([e])}handleFilesChanged(e){for(let i of e)this.pendingChangedFiles.add(i);this.fileChangeTimer&&clearTimeout(this.fileChangeTimer);let n=this.options.runtime.watch_debounce_ms??te;this.fileChangeTimer=setTimeout(()=>{this.fileChangeTimer=null,this.flushChangedFiles()},n),this.fileChangeTimer?.unref?.()}flushChangedFiles(){if(this.fileChangeTimer&&(clearTimeout(this.fileChangeTimer),this.fileChangeTimer=null),this.pendingChangedFiles.size===0)return;let e=[...this.pendingChangedFiles].sort((n,i)=>n.localeCompare(i));if(this.pendingChangedFiles.clear(),e.some(et)&&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=_.readFileSync(m.join(this.options.projectRoot,q),"utf8"),n=JSON.parse(e),i=typeof n.snapshot_id=="string"?n.snapshot_id:"";return!i||$(i)!==i?(console.warn("[vcp-site-edit] current-snapshot marker has no valid snapshot_id"),null):i}catch(e){return console.warn(`[vcp-site-edit] current-snapshot marker unreadable: ${e instanceof Error?e.message:String(e)}`),null}}async advanceSnapshotId(e){if(this.stopping||!this.isStarted||e===this.options.snapshotId)return;let n=this.options.snapshotId;this.options.snapshotId=e;try{if(this.options.historyRoot){let o=await this.bindHistorySession(e);if(!o.ok)throw new Error(`${o.code}: ${o.message}`)}else this.createRuntime()}catch(o){this.options.snapshotId=n,console.warn(`[vcp-site-edit] snapshot identity advance rolled back to ${n}: ${o instanceof Error?o.message:String(o)}`);return}let i=new Date().toISOString();for(let o of this.compositions){let s={type:"site-edit.snapshot.changed",siteId:this.options.siteId,composition:o.context,snapshotId:e,previousSnapshotId:n,at:i};for(let r of this.eventListeners)try{r(s)}catch(a){console.warn(`[vcp-site-edit] snapshot.changed listener failed: ${a instanceof Error?a.message:String(a)}`)}}try{this.options.onSnapshotIdChanged?.(e,n)}catch(o){console.warn(`[vcp-site-edit] onSnapshotIdChanged callback failed: ${o instanceof Error?o.message:String(o)}`)}}refreshCompositions(e=!1){try{let n=We(this.options.projectRoot),i=Ae(n),o=i.length>0?i:(this.options.runtime.routes??[]).map(d=>({...d})),s=Te({files:n});if(s.length===0)throw new Error("No canonical App Router composition is indexed by the preview bridge.");let r=JSON.stringify(s.filter(d=>d.context.effectiveTemplateId!==void 0).map(d=>d.entryFile).sort());if(e&&(this.launchCandidateEntries=r),this.launchCandidateEntries!==r)throw new Error("SITE_EDIT_RUNTIME_RELOAD_REQUIRED: Candidate route collection changed since preview launch");let a=new Map(this.compositions.map(d=>[E(d.context),d])),h=new Map(s.map(d=>[E(d.context),d]));if(this.runtime){for(let[d,l]of a){let S=h.get(d);(!S||S.entryFile!==l.entryFile)&&this.runtime.unregisterComposition(y(l.context))}for(let[d,l]of h){let S=a.get(d);(!S||S.entryFile!==l.entryFile)&&this.runtime.registerComposition(l.context,l.entryFile)}}return this.routes=o,this.compositions=s,this.compositionFiles=n,this.compositionResolutionError=null,this.notifyHealthChanged(),!0}catch(n){let i=n instanceof Error?n:new Error(String(n));if(this.compositionResolutionError=i,e)throw i;return this.notifyHealthChanged(),!1}}resolveComposition(e){if(this.compositionResolutionError)throw this.compositionResolutionError;let n=Oe(e.routeId,this.routes,this.options.basePath);if(!n)throw new Error(`Route is not indexed by the preview bridge: ${e.routeId}`);let i=this.routes.find(r=>r.routeId===n);if(!i)throw new Error(`Route is not indexed by the preview bridge: ${e.routeId}`);let o=_e({selector:{routeId:n,...e.templateId!==void 0?{templateId:e.templateId}:{}},files:this.compositionFiles,canonicalEntryFile:i.entryFile}),s=E(o.context);if(!this.compositions.some(r=>E(r.context)===s))throw new Error(`Composition is not registered by the preview bridge: ${s}`);return o}getInitialDocumentVersions(){return this.compositions.flatMap(e=>{let n=this.runtimeVersionFloors.get(E(e.context));return n===void 0?[]:[{composition:e.context,version:n}]})}getRuntime(){if(!this.runtime)throw new Error("VCP site edit preview bridge runtime is not ready");return this.runtime}};function ce(t){let e=new j(Be(t),oe.createServer(),!1);return e.start({listen:!1,webSocket:!1}),{engine:e.getEngine(),getHealth:()=>e.getHealth(),stop:()=>e.stop()}}function Be(t){return{tenantId:t.tenantId,siteId:t.siteId,snapshotId:t.snapshotId,projectRoot:m.resolve(t.projectRoot??process.cwd()),basePath:t.basePath??"",host:t.host??De,port:t.port??Ne,path:t.path??Ke,sessionKey:t.sessionKey??Xe(),historyRoot:t.historyRoot,allowedOrigins:t.allowedOrigins??[],runtime:t.runtime??{},onSnapshotIdChanged:t.onSnapshotIdChanged,onHealthChanged:t.onHealthChanged}}function Pe(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 We(t){let e=[],n=["app","src/app",".vcp"],i=new Set([".git",".next",".turbo","coverage","dist","node_modules","output","snapshot-store"]),o=s=>{if(!_.existsSync(s))return;let r;try{r=_.readdirSync(s,{withFileTypes:!0})}catch{return}for(let a of r){if(a.name.startsWith(".")&&a.name!==".vcp")continue;if(a.isDirectory()){if(i.has(a.name))continue;o(m.join(s,a.name));continue}if(!a.isFile())continue;let h=m.join(s,a.name),d="";try{d=_.readFileSync(h,"utf8")}catch{}e.push({path:m.relative(t,h).replaceAll(m.sep,"/"),content:d})}};for(let s of n)o(m.join(t,s));return e.sort((s,r)=>s.path.localeCompare(r.path))}function Ue(t){if(!t||typeof t!="object"||typeof t.routeId!="string")throw new Error("Normalized composition context is required.");if("effectiveTemplateId"in t)return t;let e=t;return{routeId:e.routeId,...e.templateId?{effectiveTemplateId:e.templateId}:{}}}function y(t){return{routeId:t.routeId,...t.effectiveTemplateId?{templateId:t.effectiveTemplateId}:{}}}function qe(t){return m.join(m.resolve(t.root),$(t.siteId),$(t.snapshotId),J("sha256").update(t.editingSessionId).digest("hex").slice(0,32))}function $(t){return/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(t)&&t!=="."&&t!==".."?t:J("sha256").update(t).digest("hex").slice(0,32)}function je(){let t=globalThis;return t[ne]??=new Map,t[ne]}function $e(t){return`${t.projectRoot}:${t.host}:${t.port}:${t.path}:${t.historyRoot??""}`}function W(t,e,n){let i=n??(e?.composition?{routeId:e.composition.routeId,...e.composition.templateId?{effectiveTemplateId:e.composition.templateId}:{}}:void 0);if(!i)throw new Error("A normalized composition is required to construct a mutation result.");return{ok:!1,composition:i,error:{code:t.code,message:t.message},data:{requestId:e?.id??"mutation-context",kind:e?.kind??"update-text",composition:i,target:e?.target??{kind:"node",key:""},resultVersion:e?.documentVersion??0}}}function ze(t){let e=new xe({maxPayload:ae,noServer:!0}),n=new WeakSet,i=s=>{new A({socket:new z(s),engine:t.engine,validateOperationRequest:r=>He.safeParse(r).success})},o=(s,r,a)=>{if(!Le(s,t))return;let h=Je(s,t);if(!h){r.write(`HTTP/1.1 401 Unauthorized\r
|
|
1
|
+
import{parentPort as nt,workerData as it}from"node:worker_threads";function H(t){let e=t&&typeof t=="object"?t:null,n=typeof e?.message=="string"&&e.message.length>0?e.message:String(t);return{name:typeof e?.name=="string"?e.name:"Error",message:n,...typeof e?.code=="string"&&e.code.length>0?{code:e.code}:{}}}import oe from"node:http";import _ from"node:fs";import{createHash as J,randomBytes as be,timingSafeEqual as xe}from"node:crypto";import m from"node:path";import{WebSocket as re,WebSocketServer as ke}from"ws";import{createPreviewSiteEditEngineRuntime as ve,openFileHistoryStore as _e,resolveManagedPageTemplateComposition as Te,scanSiteEditCompositionsFromFiles as Oe}from"@vcp-dev/site-edit-engine";import{resolveNextAppRouteId as Ae,scanNextAppRouterRoutesFromFiles as Me}from"@vcp-dev/site-edit-engine/next-app-router";import{SiteEditSourceWatcher as He}from"@vcp-dev/site-edit-engine/source-watcher";function Y(t){let e=new Map,n=[],i=new Map,s=[],o=t.pageComposition.status==="supported"?t.pageComposition.placementUnitKeys:[],r=new Map(o.map((c,p)=>[c,p])),a=t.pageComposition.status==="supported"?{status:"supported",containerKey:t.pageComposition.containerKey,hasBusinessMembers:t.pageComposition.hasBusinessMembers,placementUnitKeys:t.pageComposition.placementUnitKeys,placements:t.pageComposition.placements.map(c=>({placementKey:c.placementKey,placementUnitKey:c.placementUnitKey,relation:c.relation}))}:{status:"unsupported",reason:t.pageComposition.reason,diagnostics:t.pageComposition.diagnostics},h=t.entries.flatMap((c,p)=>c.dynamicDataSummary?[[p,c.dynamicDataSummary]]:[]),d=new Map(t.entries.map((c,p)=>[c.key,p])),l=[];for(let[c,p]of t.entries.entries()){let g=p.pageCompositionActionScope;if(!g)continue;if(g.kind!=="source-siblings"){l.push([c,{kind:g.kind}]);continue}let O=g.siblingKeys.map(x=>{let k=d.get(x);if(k===void 0)throw new Error("Render entry "+p.key+" references missing source sibling "+x);return k});l.push([c,{kind:"source-siblings",siblingEntryIndexes:O}])}let S=c=>{let p=e.get(c);if(typeof p=="number")return p;let g=n.length;return n.push(c),e.set(c,g),g},Q=c=>{let p=null;for(let g of le(c)){let O=`${p??"root"}\0${g}`,x=i.get(O);if(typeof x=="number"){p=x;continue}let k=s.length;s.push([p,S(g)]),i.set(O,k),p=k}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:s,entries:t.entries.map(c=>{let p=c.pageCompositionUnitKey?r.get(c.pageCompositionUnitKey)??-1:-1;if(c.pageCompositionUnitKey&&p<0)throw new Error(`Render entry ${c.key} references unknown page composition unit ${c.pageCompositionUnitKey}`);return[Q(c.key),pe(c.operationSummary),...p>=0?[p]:[]]}),...l.length>0?{pageCompositionActionScopes:l}:{},...t.entries.every(c=>c.parentKey!==void 0)?{entryParentNodeIds:t.entries.map(c=>c.parentKey===null?null:Q(c.parentKey))}:{},...h.length>0?{dynamicDataSummaries:h}:{}}}function pe(t){return(t.canUpdateText?1:0)|(t.canInsertChild?2:0)|(t.canMove?4:0)|(t.canRemove?8:0)}function le(t){if(!t)return[];let e=[],n=0,i=G(t,n);if(i<0)return e.push(t),e;for(e.push(t.slice(0,i)),n=i;n<t.length;){if(i=G(t,n+(t.startsWith("::",n)?2:1)),i<0){e.push(t.slice(n));break}e.push(t.slice(n,i)),n=i}return e}function G(t,e){let n=t.indexOf("/",e),i=t.indexOf("::",e);return n<0?i:i<0?n:Math.min(n,i)}var Z="SITE_EDIT_COMPOSITION_SESSION_MISMATCH",P="SITE_EDIT_COMPOSITION_SESSION_REQUIRED";var f=class t{constructor(){}static parseMessage(e,n={}){let i=JSON.parse(e);if(!t.isMessage(i,n))throw new Error("Invalid site edit bridge message");return i}static stringifyMessage(e){return JSON.stringify(e)}static extractRequestInfo(e){if(u(e)&&u(e.payload)){let n=typeof e.payload.id=="string"?e.payload.id:"unknown",i=this.isRequestKind(e.payload.kind)?e.payload.kind:"get-document";return{id:n,kind:i}}return{id:"unknown",kind:"get-document"}}static isRequestKind(e){return e==="initialize-session"||e==="get-document"||e==="get-history-status"||e==="get-style-context"||e==="get-object-edit-context"||e==="get-class-name-source"||e==="get-source-tree"||e==="get-source-file"||e==="resolve-source-location"||e==="execute"||e==="get-operation-result"||e==="undo"||e==="redo"}static isMessage(e,n={}){return!u(e)||typeof e.type!="string"?!1:e.type==="request"?me(e.payload,n):e.type==="response"||e.type==="error"?u(e.payload)&&typeof e.payload.id=="string":e.type==="event"?u(e.payload)&&u(e.payload.event):e.type==="auth"?u(e.payload)&&typeof e.payload.key=="string":e.type==="ping"||e.type==="pong"?u(e.payload)&&typeof e.payload.id=="string":e.type==="auth-ok"&&u(e.payload)&&e.payload.ok===!0}},A=class{constructor(e){this.options=e,this.session={subscribedCompositionKeys:new Set},this.messageQueue=new B,this.eventDispatcher=new V(n=>{this.sendJson(n)}),this.unsubscribe=e.engine.subscribe(n=>{this.handleEngineEvent(n)}),e.socket.onmessage=n=>{let i=fe(n.data);if(i!==null){this.sendJson({type:"pong",payload:{id:i}});return}try{this.messageQueue.enqueue(()=>this.handleRawMessage(n.data))}catch(s){this.sendJson({type:"error",payload:{id:"unknown",kind:"get-document",message:s instanceof Error?s.message:"Bridge queue overflow"}}),e.socket.close(1013,"bridge busy")}},e.socket.onclose=()=>{this.unsubscribe(),this.session.activeComposition=void 0,this.session.subscribedCompositionKeys.clear()}}async handleMessage(e){try{let n=e;if(n.type!=="request")return;let i=n.payload,{id:s}=i;switch(i.kind){case"initialize-session":{let o=D(i),r=await this.resolve(o),a=await this.options.engine.initializeSession({composition:r.context,...i.mutationContext?{mutationContext:i.mutationContext}:{}});this.activateSession(r.context),this.sendJson({type:"response",payload:{id:s,kind:i.kind,result:I({...a,data:{...a.data,document:ee(a.data.document)}},r.context)}});return}case"get-document":{let o=await this.resolveWireContext(i),r=await this.options.engine.getDocument(o);this.sendResult(s,i.kind,Ee(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,I(r,o));return}case"get-style-context":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,I(await this.options.engine.getStyleContext(o),o));return}case"get-object-edit-context":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,I(await this.options.engine.getObjectEditContext(i.key,o,i.selectionRef),o));return}case"get-class-name-source":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,I(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,I(await this.options.engine.getSourceTree(o),o));return}case"get-source-file":{let o=await this.resolveWireContext(i);this.sendResult(s,i.kind,I(await this.options.engine.getSourceFile({path:i.path,composition:o}),o));return}case"resolve-source-location":{let o=await this.resolveWireContext(i),r=I(await this.options.engine.resolveSourceLocation({key:i.key,composition:o}),o);this.sendResult(s,i.kind,r);return}case"execute":case"get-operation-result":{let o=await this.resolveOperationWireContext(i.request),r=await this.resolveWireContext(i);if(w(o)!==w(r))throw new C(Z,"The execute request composition does not match its operation composition.");let a=await this.normalizeOperationRequest(i.request,o);if(i.kind==="get-operation-result"){this.sendResult(s,i.kind,await this.options.engine.getOperationResult?.(a)??null);return}await this.handleBufferedOperation(s,i.kind,()=>this.options.engine.execute(a));return}case"undo":case"redo":{let o=await this.resolveWireContext(i);await this.handleBufferedOperation(s,i.kind,()=>i.kind==="undo"?this.options.engine.undo(o):this.options.engine.redo(o));return}}}catch(n){let i=f.extractRequestInfo(e);this.sendJson({type:"error",payload:{...i,message:K(n),code:F(n)}})}}async resolve(e){return this.options.engine.resolveComposition(e)}async resolveAndAssert(e){let n=await this.resolve(e),i=this.session.activeComposition;if(!i)throw new C(P,"Initialize a composition session before issuing this request.");if(w(i)!==w(n.context))throw new C(Z,"The request composition does not match the active socket session.");return n.context}async resolveWireContext(e){let n=D(e);return this.resolveAndAssert(n)}async resolveOperationWireContext(e){let n=we(e);return this.resolveAndAssert(n)}activateSession(e){this.session.activeComposition=e,this.session.subscribedCompositionKeys.clear(),this.session.subscribedCompositionKeys.add(w(e))}async normalizeOperationRequest(e,n){let i={...e,composition:X(n)};if(i.target.kind==="route"){let s=i.target,o=D(s),r=await this.resolveAndAssert(o);i.target={...s,composition:X(r)}}return i}handleEngineEvent(e){let n=e?.composition;if(!Se(n))return;let i=w(n);this.session.subscribedCompositionKeys.has(i)&&(this.eventDispatcher.push(e),e.type==="site-edit.graph.invalidated"&&i===Ce(this.session)&&(this.session.activeComposition=void 0,this.session.subscribedCompositionKeys.delete(i)))}sendResult(e,n,i){this.sendJson({type:"response",payload:{id:e,kind:n,result:i}})}async handleRawMessage(e){try{await this.handleMessage(f.parseMessage(e,{validateOperationRequest:this.options.validateOperationRequest}))}catch(n){let i=Re(e);this.sendJson({type:"error",payload:{...i,message:K(n),code:F(n)}})}}sendJson(e){this.options.socket.send(f.stringifyMessage(e))}async handleBufferedOperation(e,n,i){this.eventDispatcher.beginBuffering();try{let s=await i();this.sendResult(e,n,s)}catch(s){this.sendJson({type:"error",payload:{id:e,kind:n,message:K(s),code:F(s)}})}finally{this.eventDispatcher.flush()}}},ge=256;function fe(t){if(t.length>ge||!t.includes('"ping"'))return null;try{let e=JSON.parse(t);return u(e)&&e.type==="ping"&&u(e.payload)&&typeof e.payload.id=="string"?e.payload.id:null}catch{return null}}var C=class extends Error{constructor(e,n){super(n),this.code=e,this.name="BridgeProtocolError"}},V=class{constructor(e){this.send=e,this.bufferedEvents=null}push(e){let n={type:"event",payload:{event:e}};if(this.bufferedEvents){this.bufferedEvents.push(n);return}this.send(n)}beginBuffering(){this.bufferedEvents=[]}flush(){let e=this.bufferedEvents??[];this.bufferedEvents=null,e.forEach(n=>this.send(n))}},B=class{constructor(e=64){this.maxQueued=e,this.queue=Promise.resolve(),this.queued=0}enqueue(e){if(this.queued>=this.maxQueued)throw new Error("Bridge request queue is full");this.queued+=1;let n=async()=>{this.queued-=1,await e()},i=this.queue.then(n,n);return this.queue=i.then(()=>{},()=>{}),i}};function me(t,e){if(!u(t)||typeof t.id!="string"||!f.isRequestKind(t.kind))return!1;let n=v(t.composition);switch(t.kind){case"initialize-session":return n&&(t.mutationContext===void 0||N(t.mutationContext));case"get-document":case"get-style-context":return n;case"get-object-edit-context":return typeof t.key=="string"&&n&&ye(t.selectionRef);case"get-class-name-source":case"resolve-source-location":return typeof t.key=="string"&&n;case"get-history-status":return n;case"get-source-tree":return n;case"get-source-file":return typeof t.path=="string"&&n;case"execute":case"get-operation-result":return n&&Ie(t.request)&&(t.request.mutationContext===void 0||N(t.request.mutationContext))&&(e.validateOperationRequest?.(t.request)??!0);case"undo":case"redo":return n&&t.mutationContext===void 0||n&&N(t.mutationContext)}}function ye(t){if(t===void 0)return!0;if(!u(t)||typeof t.key!="string"||t.key.length===0)return!1;let e=t.instanceIndex,n=t.instanceCount;return e!==void 0&&(typeof e!="number"||!Number.isInteger(e)||e<0)||n!==void 0&&(typeof n!="number"||!Number.isInteger(n)||n<=0)||typeof e=="number"&&typeof n=="number"&&e>=n?!1:Object.keys(t).every(i=>i==="key"||i==="instanceIndex"||i==="instanceCount")}function Ie(t){return u(t)&&typeof t.id=="string"&&typeof t.siteId=="string"&&typeof t.baseSnapshotId=="string"&&v(t.composition)&&typeof t.kind=="string"&&u(t.target)&&(t.target.kind!=="route"||v(t.target.composition))&&typeof t.documentVersion=="number"&&Number.isInteger(t.documentVersion)&&t.documentVersion>=0&&u(t.params)}function v(t){return u(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 Se(t){return u(t)&&typeof t.routeId=="string"&&(t.effectiveTemplateId===void 0||typeof t.effectiveTemplateId=="string")}function D(t){if(v(t.composition))return t.composition;throw new C(P,"A composition selector is required for this request.")}function we(t){if(u(t)&&v(t.composition))return t.composition;throw new C(P,"A composition selector is required for execute.")}function X(t){return{routeId:t.routeId,...t.effectiveTemplateId?{templateId:t.effectiveTemplateId}:{}}}function Ce(t){return t.activeComposition?w(t.activeComposition):null}function w(t){return JSON.stringify([t.routeId,t.effectiveTemplateId??null])}function I(t,e){return u(t)&&t.ok===!0?{...t,composition:e}:t}function Ee(t,e){return!u(t)||t.ok!==!0?t:{...t,...e?{composition:e}:{},data:ee(t.data)}}function ee(t){let e=t;return Y(e.routeId?e:{...e,routeId:e.composition.routeId})}function u(t){return typeof t=="object"&&t!==null}function N(t){return u(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 F(t){if(!(!u(t)||typeof t.code!="string"||t.code.length===0))return t.code}function K(t){return t instanceof Error||u(t)&&typeof t.message=="string"&&t.message.length>0?t.message:"Unknown websocket operation failure"}function Re(t){try{return f.extractRequestInfo(JSON.parse(t))}catch{return{id:"unknown",kind:"get-document"}}}var M=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 E}from"@vcp-dev/contracts";var Ne="127.0.0.1",Fe=30218,Ke="/__vcp/site-edit/bridge",ae=6*1024*1024,Ve=ae*2,Be=3e3,te=50,q=".vcp/current-snapshot.json",ne="__VCP_SITE_EDIT_BRIDGE_SERVERS__";var j=class{constructor(e,n=oe.createServer((o,r)=>{r.writeHead(404),r.end("VCP site edit bridge server")}),i=!0,s={}){this.options=e,this.server=n,this.closeHttpServerOnStop=i,this.dependencies=s,this.runtime=null,this.activeHistorySessionId=null,this.historySessionTransition=Promise.resolve(),this.mutationQueue=new M,this.operationReceipts=new Map,this.eventListeners=new Set,this.routes=[],this.compositions=[],this.compositionFiles=[],this.compositionResolutionError=null,this.launchCandidateEntries=null,this.stopWatching=null,this.stopWebSocketServer=null,this.pendingChangedFiles=new Set,this.fileChangeTimer=null,this.isStarted=!1,this.stopping=!1,this.runtimeVersionFloors=new Map,this.activeHistoryStore=null,this.versionPersistence=Promise.resolve(),this.versionCheckpoints=new WeakMap,this.bridgeEngine=null,this.lastNotifiedHealth=null}start(e={}){if(!this.isStarted){this.stopping=!1;try{_.mkdirSync(m.join(this.options.projectRoot,".vcp"),{recursive:!0})}catch(n){console.warn(`[vcp-site-edit] failed to ensure .vcp directory: ${n instanceof Error?n.message:String(n)}`)}if(this.refreshCompositions(!0),this.isStarted=!0,this.createRuntime(),this.bridgeEngine=this.createBridgeEngine(),e.webSocket!==!1){let n=Le({server:this.server,path:this.options.path,sessionKey:this.options.sessionKey,host:this.options.host,allowedOrigins:this.options.allowedOrigins,engine:this.bridgeEngine});this.stopWebSocketServer=n.stop}this.stopWatching=new He({projectRoot:this.options.projectRoot,watch_dirs:We(this.options.runtime.watch_dirs),interval_ms:this.options.runtime.watch_interval_ms,debounce_ms:this.options.runtime.watch_debounce_ms??te,max_dirs:this.options.runtime.watch_max_dirs,max_files:this.options.runtime.watch_max_files,max_depth:this.options.runtime.watch_max_depth,max_startup_ms:this.options.runtime.watch_max_startup_ms,on_change:n=>this.handleFileChanged(n),on_batch_change:n=>this.handleFilesChanged(n)}).start(),e.listen!==!1&&this.server.listen(this.options.port,this.options.host),this.notifyHealthChanged()}}getEngine(){if(!this.bridgeEngine)throw new Error("VCP site edit preview bridge runtime is not ready");return this.bridgeEngine}getHealth(){let e=!!this.runtime&&!this.compositionResolutionError;return{ok:this.isStarted&&e,bridgePath:this.options.path,runtimeReady:e,routesIndexed:this.routes.length,sessionRequired:!!this.options.sessionKey}}stop(){this.stopping=!0,this.stopWatching?.(),this.stopWatching=null,this.flushChangedFiles(),this.fileChangeTimer&&(clearTimeout(this.fileChangeTimer),this.fileChangeTimer=null),this.stopWebSocketServer?.(),this.stopWebSocketServer=null,this.runtime?.dispose(),this.runtime=null,this.compositions=[],this.compositionFiles=[],this.compositionResolutionError=null,this.closeHttpServerOnStop&&this.server.close();let e=$e(),n=ze(this.options);e.get(n)===this&&e.delete(n),this.isStarted=!1,this.notifyHealthChanged()}notifyHealthChanged(){let e=this.options.onHealthChanged;if(!e)return;let n=this.getHealth(),i=JSON.stringify(n);if(i!==this.lastNotifiedHealth){this.lastNotifiedHealth=i;try{e(n)}catch(s){console.warn(`[vcp-site-edit] onHealthChanged callback failed: ${s instanceof Error?s.message:String(s)}`)}}}createRuntime(e,n=null){let i=this.runtime;this.activeHistoryStore=e??null;let s=(this.dependencies.createRuntime??ve)({...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)},...e?{historyStore:e}:{},...this.getInitialDocumentVersions().length>0?{initialDocumentVersions:this.getInitialDocumentVersions()}:{}});this.runtime=s,this.activeHistorySessionId=n,i?.dispose(),this.notifyHealthChanged()}createBridgeEngine(){return{resolveComposition:e=>this.resolveComposition(e),initializeSession:e=>this.mutationQueue.run(async()=>{let n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)throw new Error(`${n.code}: ${n.message}`);let i=qe(e.composition),s=this.getRuntime(),o=y(i);await s.initializeComposition(o);let a=s.getDocument(o).data;await this.recordRuntimeVersion(a.version,i);let h=(await s.getHistoryStatus()).data;return{ok:!0,composition:i,data:{document:a,historyStatus:h}}}),getDocument:async e=>{let n=this.getRuntime(),i=y(e);await n.initializeComposition(i);let s=n.getDocument(i);return await this.recordRuntimeVersion(s.data.version,e),{...s,composition:e}},getHistoryStatus:async e=>({...await this.getRuntime().getHistoryStatus(),composition:e}),getStyleContext:async e=>this.getRuntime().getStyleContext(y(e)),getObjectEditContext:async(e,n,i)=>this.getRuntime().getObjectEditContext(e,y(n),i),getClassNameSource:async(e,n)=>this.getRuntime().getClassNameSource(e,y(n)),getSourceTree:async e=>this.getRuntime().getSourceTree(y(e)),getSourceFile:async e=>this.getRuntime().getSourceFile({path:e.path,composition:y(e.composition)}),resolveSourceLocation:async e=>this.getRuntime().resolveSourceLocation({key:e.key,composition:y(e.composition)}),execute:(e,n)=>this.executeWithReceipt(e,()=>this.mutationQueue.run(async()=>{let i=await this.bindHistorySession(this.options.snapshotId);if(!i.ok)return W(i,e);let s=await this.getRuntime().executeOperation(e);return s.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(s.data.resultVersion,s.composition),s})),getOperationResult:e=>{if(e.siteId!==this.options.siteId||e.baseSnapshotId!==this.options.snapshotId)return null;let n=this.operationReceipts.get(this.operationReceiptKey(e));return n?.fingerprint===this.operationFingerprint(e)?n.result:null},undo:e=>this.mutationQueue.run(async()=>{let n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)return W(n,void 0,e);let i=await this.getRuntime().undo();return i.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(i.data.resultVersion,i.composition??e),i.composition?i:{...i,composition:e}}),redo:e=>this.mutationQueue.run(async()=>{let n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)return W(n,void 0,e);let i=await this.getRuntime().redo();return i.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(i.data.resultVersion,i.composition??e),i.composition?i:{...i,composition:e}}),subscribe:e=>(this.eventListeners.add(e),()=>this.eventListeners.delete(e))}}operationReceiptKey(e){return JSON.stringify([e.siteId,e.baseSnapshotId,e.id])}operationFingerprint(e){return J("sha256").update(JSON.stringify(e)).digest("hex")}executeWithReceipt(e,n){if(e.siteId!==this.options.siteId||e.baseSnapshotId!==this.options.snapshotId)return n();let i=this.operationReceiptKey(e),s=this.operationFingerprint(e),o=this.operationReceipts.get(i);if(o)return o.fingerprint!==s?Promise.reject(new Error("Operation ID was reused with a different request.")):o.result;let r={fingerprint:s,result:n(),settled:!1};return this.operationReceipts.set(i,r),r.result.then(()=>{r.settled=!0;for(let[a,h]of this.operationReceipts){if(this.operationReceipts.size<=256)break;h.settled&&this.operationReceipts.delete(a)}},()=>{this.operationReceipts.delete(i)}),r.result}async bindHistorySession(e){if(!this.options.historyRoot)return{ok:!1,code:"RECOVERY_PERSIST_FAILED",message:"Durable edit history is not configured."};if(this.activeHistorySessionId===e)return{ok:!0};let n=this.historySessionTransition.then(async()=>{if(this.activeHistorySessionId===e)return;let i=await(this.dependencies.openHistoryStore??_e)(je({root:this.options.historyRoot,siteId:this.options.siteId,snapshotId:this.options.snapshotId,editingSessionId:e}));if(!this.isStarted)return;let s=i.readDocumentVersion?await i.readDocumentVersion():0,o=this.versionCheckpoints.get(i);o?o.durableVersion=Math.max(o.durableVersion,s):this.versionCheckpoints.set(i,{durableVersion:s,requestedVersion:s,pending:null});let r=this.compositions[0]?.context;if(r){let a=E(r);this.runtimeVersionFloors.set(a,Math.max(this.runtimeVersionFloors.get(a)??0,s))}this.createRuntime(i,e)});this.historySessionTransition=n.catch(()=>{});try{return await n,{ok:!0}}catch{return{ok:!1,code:"RECOVERY_PERSIST_FAILED",message:"Durable edit history could not be opened."}}}recordRuntimeVersion(e,n){let i=n?E(n):null;i&&this.runtimeVersionFloors.set(i,Math.max(this.runtimeVersionFloors.get(i)??0,e));let s=this.activeHistoryStore;if(!s?.writeDocumentVersion)return Promise.resolve();let o=i?this.runtimeVersionFloors.get(i)??e:e,r=this.versionCheckpoints.get(s);if(r||(r={durableVersion:0,requestedVersion:0,pending:null},this.versionCheckpoints.set(s,r)),o<=r.durableVersion)return Promise.resolve();if(r.requestedVersion=Math.max(r.requestedVersion,o),r.pending)return r.pending;let a=r,h=this.versionPersistence.then(async()=>{try{for(;a.requestedVersion>a.durableVersion;){let d=a.requestedVersion;await s.writeDocumentVersion(d),a.durableVersion=Math.max(a.durableVersion,d)}}catch{console.warn("[vcp-site-edit] document version checkpoint persistence failed")}finally{a.pending=null}});return a.pending=h,this.versionPersistence=h,h}handleFileChanged(e){this.handleFilesChanged([e])}handleFilesChanged(e){for(let i of e)this.pendingChangedFiles.add(i);this.fileChangeTimer&&clearTimeout(this.fileChangeTimer);let n=this.options.runtime.watch_debounce_ms??te;this.fileChangeTimer=setTimeout(()=>{this.fileChangeTimer=null,this.flushChangedFiles()},n),this.fileChangeTimer?.unref?.()}flushChangedFiles(){if(this.fileChangeTimer&&(clearTimeout(this.fileChangeTimer),this.fileChangeTimer=null),this.pendingChangedFiles.size===0)return;let e=[...this.pendingChangedFiles].sort((s,o)=>s.localeCompare(o));this.pendingChangedFiles.clear();let n=e.some(he)?this.scheduleSnapshotIdentityAdvance():!1,i=e.filter(s=>!tt(s));if(!(i.length===0&&!n)&&this.refreshCompositions(!1))for(let s of i)this.runtime?.notifyFileChanged(s)}scheduleSnapshotIdentityAdvance(){if(this.stopping||!this.isStarted)return!1;let e=this.readCurrentSnapshotMarker();return!e||e===this.options.snapshotId?!1:(this.mutationQueue.run(()=>this.advanceSnapshotId(e)).catch(n=>{console.warn(`[vcp-site-edit] snapshot identity advance failed: ${n instanceof Error?n.message:String(n)}`)}),!0)}readCurrentSnapshotMarker(){try{let e=_.readFileSync(m.join(this.options.projectRoot,q),"utf8"),n=JSON.parse(e),i=typeof n.snapshot_id=="string"?n.snapshot_id:"";return!i||$(i)!==i?(console.warn("[vcp-site-edit] current-snapshot marker has no valid snapshot_id"),null):i}catch(e){return console.warn(`[vcp-site-edit] current-snapshot marker unreadable: ${e instanceof Error?e.message:String(e)}`),null}}async advanceSnapshotId(e){if(this.stopping||!this.isStarted||e===this.options.snapshotId)return;let n=this.options.snapshotId;this.options.snapshotId=e;try{if(this.options.historyRoot){let s=await this.bindHistorySession(e);if(!s.ok)throw new Error(`${s.code}: ${s.message}`)}else this.createRuntime()}catch(s){this.options.snapshotId=n,console.warn(`[vcp-site-edit] snapshot identity advance rolled back to ${n}: ${s instanceof Error?s.message:String(s)}`);return}let i=new Date().toISOString();for(let s of this.compositions){let o={type:"site-edit.snapshot.changed",siteId:this.options.siteId,composition:s.context,snapshotId:e,previousSnapshotId:n,at:i};for(let r of this.eventListeners)try{r(o)}catch(a){console.warn(`[vcp-site-edit] snapshot.changed listener failed: ${a instanceof Error?a.message:String(a)}`)}}try{this.options.onSnapshotIdChanged?.(e,n)}catch(s){console.warn(`[vcp-site-edit] onSnapshotIdChanged callback failed: ${s instanceof Error?s.message:String(s)}`)}}refreshCompositions(e=!1){try{let n=Ue(this.options.projectRoot),i=Me(n),s=i.length>0?i:(this.options.runtime.routes??[]).map(d=>({...d})),o=Oe({files:n});if(o.length===0)throw new Error("No canonical App Router composition is indexed by the preview bridge.");let r=JSON.stringify(o.filter(d=>d.context.effectiveTemplateId!==void 0).map(d=>d.entryFile).sort());if(e&&(this.launchCandidateEntries=r),this.launchCandidateEntries!==r)throw new Error("SITE_EDIT_RUNTIME_RELOAD_REQUIRED: Candidate route collection changed since preview launch");let a=new Map(this.compositions.map(d=>[E(d.context),d])),h=new Map(o.map(d=>[E(d.context),d]));if(this.runtime){for(let[d,l]of a){let S=h.get(d);(!S||S.entryFile!==l.entryFile)&&this.runtime.unregisterComposition(y(l.context))}for(let[d,l]of h){let S=a.get(d);(!S||S.entryFile!==l.entryFile)&&this.runtime.registerComposition(l.context,l.entryFile)}}return this.routes=s,this.compositions=o,this.compositionFiles=n,this.compositionResolutionError=null,this.notifyHealthChanged(),!0}catch(n){let i=n instanceof Error?n:new Error(String(n));if(this.compositionResolutionError=i,e)throw i;return this.notifyHealthChanged(),!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 i=this.routes.find(r=>r.routeId===n);if(!i)throw new Error(`Route is not indexed by the preview bridge: ${e.routeId}`);let s=Te({selector:{routeId:n,...e.templateId!==void 0?{templateId:e.templateId}:{}},files:this.compositionFiles,canonicalEntryFile:i.entryFile}),o=E(s.context);if(!this.compositions.some(r=>E(r.context)===o))throw new Error(`Composition is not registered by the preview bridge: ${o}`);return s}getInitialDocumentVersions(){return this.compositions.flatMap(e=>{let n=this.runtimeVersionFloors.get(E(e.context));return n===void 0?[]:[{composition:e.context,version:n}]})}getRuntime(){if(!this.runtime)throw new Error("VCP site edit preview bridge runtime is not ready");return this.runtime}};function ce(t){let e=new j(Pe(t),oe.createServer(),!1);return e.start({listen:!1,webSocket:!1}),{engine:e.getEngine(),getHealth:()=>e.getHealth(),stop:()=>e.stop()}}function Pe(t){return{tenantId:t.tenantId,siteId:t.siteId,snapshotId:t.snapshotId,projectRoot:m.resolve(t.projectRoot??process.cwd()),basePath:t.basePath??"",host:t.host??Ne,port:t.port??Fe,path:t.path??Ke,sessionKey:t.sessionKey??et(),historyRoot:t.historyRoot,allowedOrigins:t.allowedOrigins??[],runtime:t.runtime??{},onSnapshotIdChanged:t.onSnapshotIdChanged,onHealthChanged:t.onHealthChanged}}function We(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 Ue(t){let e=[],n=["app","src/app",".vcp"],i=new Set([".git",".next",".turbo","coverage","dist","node_modules","output","snapshot-store"]),s=o=>{if(!_.existsSync(o))return;let r;try{r=_.readdirSync(o,{withFileTypes:!0})}catch{return}for(let a of r){if(a.name.startsWith(".")&&a.name!==".vcp")continue;if(a.isDirectory()){if(i.has(a.name))continue;s(m.join(o,a.name));continue}if(!a.isFile())continue;let h=m.join(o,a.name),d="";try{d=_.readFileSync(h,"utf8")}catch{}e.push({path:m.relative(t,h).replaceAll(m.sep,"/"),content:d})}};for(let o of n)s(m.join(t,o));return e.sort((o,r)=>o.path.localeCompare(r.path))}function qe(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 je(t){return m.join(m.resolve(t.root),$(t.siteId),$(t.snapshotId),J("sha256").update(t.editingSessionId).digest("hex").slice(0,32))}function $(t){return/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(t)&&t!=="."&&t!==".."?t:J("sha256").update(t).digest("hex").slice(0,32)}function $e(){let t=globalThis;return t[ne]??=new Map,t[ne]}function ze(t){return`${t.projectRoot}:${t.host}:${t.port}:${t.path}:${t.historyRoot??""}`}function W(t,e,n){let i=n??(e?.composition?{routeId:e.composition.routeId,...e.composition.templateId?{effectiveTemplateId:e.composition.templateId}:{}}:void 0);if(!i)throw new Error("A normalized composition is required to construct a mutation result.");return{ok:!1,composition:i,error:{code:t.code,message:t.message},data:{requestId:e?.id??"mutation-context",kind:e?.kind??"update-text",composition:i,target:e?.target??{kind:"node",key:""},resultVersion:e?.documentVersion??0}}}function Le(t){let e=new ke({maxPayload:ae,noServer:!0}),n=new WeakSet,i=o=>{new A({socket:new z(o),engine:t.engine,validateOperationRequest:r=>De.safeParse(r).success})},s=(o,r,a)=>{if(!Je(o,t))return;let h=Qe(o,t);if(!h){r.write(`HTTP/1.1 401 Unauthorized\r
|
|
2
2
|
Connection: close\r
|
|
3
3
|
\r
|
|
4
|
-
`),r.destroy();return}h.authenticatedByHeader&&n.add(
|
|
4
|
+
`),r.destroy();return}h.authenticatedByHeader&&n.add(o),e.handleUpgrade(o,r,a,d=>{e.emit("connection",d,o)})};return t.server.on("upgrade",s),e.on("connection",(o,r)=>{if(n.has(r)){i(o);return}Ge(o,t.sessionKey,()=>{i(o)})}),e.stop=()=>{t.server.off("upgrade",s);for(let o of e.clients)o.close(1001,"bridge stopped");e.close()},e}var z=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===re.OPEN){if(this.socket.bufferedAmount+Buffer.byteLength(e,"utf8")>Ve){this.socket.close(1013,"bridge backpressure");return}this.socket.send(e)}}close(e,n){this.socket.close(e,n)}};function Je(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=U(t.headers["x-vcp-site-edit-key"]),s=de(i,e.sessionKey),o=U(t.headers.host),r=U(t.headers.origin);return o&&!Ye(o,e.host,r)?null:r?Xe(r,o,e.allowedOrigins)?{authenticatedByHeader:s}:null:s?{authenticatedByHeader:!0}:null}function Ge(t,e,n){let i=setTimeout(()=>{t.close(1008,"bridge authentication timeout")},Be),s,o=()=>{clearTimeout(i),t.off("message",s),t.off("close",o)},r=()=>{o(),t.close(1008,"bridge authentication failed")};s=a=>{try{let h=f.parseMessage(a.toString());if(h.type!=="auth"||!de(h.payload.key,e)){r();return}o(),t.readyState===re.OPEN&&t.send(f.stringifyMessage({type:"auth-ok",payload:{ok:!0}})),n()}catch{r()}},t.on("message",s),t.on("close",o)}function de(t,e){if(!t)return!1;let n=Buffer.from(t),i=Buffer.from(e);return n.length===i.length&&xe(n,i)}function Ye(t,e,n){let i=se(t),s=se(e);return i===s||ie(s)&&ie(i)&&(!n||L(n,t))||Ze(s)&&(!n||L(n,t))}function Ze(t){return t==="0.0.0.0"||t==="::"}function ie(t){return t==="localhost"||t==="127.0.0.1"||t==="::1"}function Xe(t,e,n){return n.includes(t)||(e?L(t,e):!1)}function L(t,e){try{return new URL(t).host===ue(e)}catch{return!1}}function se(t){let e=ue(t);return e.startsWith("[")?e.slice(1,e.indexOf("]")):e.split(":").length-1===1?e.split(":",1)[0]??"":e}function ue(t){return t.trim().toLowerCase()}function U(t){return Array.isArray(t)?t[0]:t}function et(){return be(32).toString("base64url")}function he(t){let e=t.replaceAll("\\","/");return e===q||e.endsWith(`/${q}`)}function tt(t){let e=t.replaceAll("\\","/");return he(t)||e===".vcp/workspace-state.json"||e.startsWith(".vcp/snapshot-store/")}var b=nt;if(!b)throw new Error("site edit engine worker must run inside worker_threads");var R=t=>{b.postMessage(t)},st=(t,e)=>{try{b.postMessage({type:"result",id:t,ok:!0,value:e})}catch(n){if(n instanceof Error&&n.name==="DataCloneError"){b.postMessage({type:"result",id:t,ok:!0,value:e===void 0?void 0:JSON.parse(JSON.stringify(e))});return}throw n}},{options:ot}=it,T;try{T=ce({...ot,onSnapshotIdChanged:(t,e)=>{R({type:"snapshot-id-changed",next:t,previous:e})},onHealthChanged:t=>{R({type:"health",health:t})}})}catch(t){R({type:"start-failed",error:H(t)}),process.exit(1)}T.engine.subscribe(t=>{R({type:"event",event:t})});var rt=async t=>{try{let e=T.engine[t.method],n=await e(...t.args);st(t.id,n)}catch(e){R({type:"result",id:t.id,ok:!1,error:H(e)})}};b.on("message",t=>{if(t.type==="call"){rt(t);return}t.type==="stop"&&(T.stop(),b.close())});R({type:"ready",health:T.getHealth()});
|