@vcp-dev/site-edit-bridge 0.10.27 → 0.10.29

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/client.d.ts CHANGED
@@ -42,6 +42,7 @@ export type SiteEditBridgeClient = {
42
42
  }): Promise<SiteEditCommandSuccess<SiteEditSourceFileResponse>>;
43
43
  resolveSourceLocation(input: SiteEditResolveSourceLocationInput): Promise<SiteEditCommandSuccess<SiteEditSourceLocation>>;
44
44
  execute(request: SiteEditOperationRequest | Record<string, unknown>, mutationContext?: SiteEditMutationContext): Promise<SiteEditOperationCommandResult>;
45
+ getOperationResult?(request: SiteEditOperationRequest): Promise<SiteEditOperationCommandResult | null>;
45
46
  undo(composition: SiteEditBridgeCompositionInput, mutationContext?: SiteEditMutationContext): Promise<SiteEditOperationCommandResult>;
46
47
  redo(composition: SiteEditBridgeCompositionInput, mutationContext?: SiteEditMutationContext): Promise<SiteEditOperationCommandResult>;
47
48
  subscribe(listener: (event: SiteEditEvent) => void): () => void;
@@ -359,6 +360,7 @@ export declare class SiteEditWebSocketClient implements SiteEditBridgeClient {
359
360
  textPreview?: string | undefined;
360
361
  }>>;
361
362
  execute(request: SiteEditOperationRequest | Record<string, unknown>, _mutationContext?: SiteEditMutationContext): Promise<SiteEditOperationCommandResult>;
363
+ getOperationResult(request: SiteEditOperationRequest): Promise<SiteEditOperationCommandResult | null>;
362
364
  undo(composition: SiteEditBridgeCompositionInput, _mutationContext?: SiteEditMutationContext): Promise<SiteEditOperationCommandResult>;
363
365
  redo(composition: SiteEditBridgeCompositionInput, _mutationContext?: SiteEditMutationContext): Promise<SiteEditOperationCommandResult>;
364
366
  subscribe(listener: (event: SiteEditEvent) => void): () => void;
package/dist/client.js CHANGED
@@ -1 +1 @@
1
- function O(t){if(!P(t)){if(t.encoding==="segment-trie-v1")throw new Error("Invalid compact render document");return t}let e=new Map,n=t.pageComposition.status==="supported"?t.pageComposition.placementUnitKeys:[],o=new Map(t.dynamicDataSummaries??[]),i=new Map(t.pageCompositionActionScopes??[]),r=c=>{let s=e.get(c);if(s)return s;let a=t.nodes[c];if(!a)throw new Error(`Missing compact document node ${c}`);let[u,d]=a,p=t.tokens[d];if(typeof p!="string")throw new Error(`Missing compact document token ${d}`);let y=`${u===null?"":r(u)}${p}`;return e.set(c,y),y};return{siteId:t.siteId,snapshotId:t.snapshotId,composition:{...t.composition},routeId:t.composition.routeId,version:t.version,pageComposition:t.pageComposition,entries:t.entries.map((c,s)=>{let[a,u,d]=c,p=d===void 0?void 0:n[d];if(d!==void 0&&!p)throw new Error(`Missing page composition unit ${d}`);let y=t.entryParentNodeIds?.[s],w=i.get(s),D=w?.kind==="source-siblings"?{kind:"source-siblings",siblingKeys:w.siblingEntryIndexes.map(A=>{let _=t.entries[A];if(!_)throw new Error(`Missing source sibling entry ${A}`);return r(_[0])})}:w;return{key:r(a),...t.entryParentNodeIds?{parentKey:y===null?null:r(y)}:{},...p?{pageCompositionUnitKey:p}:{},...D?{pageCompositionActionScope:D}:{},operationSummary:F(u),...o.get(s)?{dynamicDataSummary:o.get(s)}:{}}})}}function F(t){return{canUpdateText:(t&1)!==0,canInsertChild:(t&2)!==0,canMove:(t&4)!==0,canRemove:(t&8)!==0}}function P(t){if(typeof t!="object"||t===null)return!1;let e=t;if(e.encoding!=="segment-trie-v1"||typeof e.siteId!="string"||typeof e.snapshotId!="string"||!U(e.composition)||typeof e.routeId!="string"||e.routeId!==e.composition.routeId||!Number.isInteger(e.version)||e.version<0||!S(e.pageComposition)||!Array.isArray(e.tokens)||!e.tokens.every(s=>typeof s=="string")||!Array.isArray(e.nodes)||!Array.isArray(e.entries))return!1;let n=e.nodes;if(!n.every((s,a)=>Array.isArray(s)&&s.length===2&&(s[0]===null||l(s[0])&&s[0]<a)&&l(s[1])&&s[1]<e.tokens.length)||!e.entries.every(s=>Array.isArray(s)&&(s.length===2||s.length===3)&&l(s[0])&&s[0]<n.length&&l(s[1])&&s[1]<=15&&(s.length===2||l(s[2]))))return!1;let o=e.entryParentNodeIds;if(o!==void 0&&(!Array.isArray(o)||o.length!==e.entries.length||!o.every(s=>s===null||l(s)&&s<n.length)))return!1;let i=e.dynamicDataSummaries,r=e.pageCompositionActionScopes;return(r===void 0||Array.isArray(r)&&r.every(s=>{if(!Array.isArray(s)||s.length!==2||!l(s[0])||s[0]>=e.entries.length||!S(s[1])||!["route-unit","source-siblings","unavailable"].includes(String(s[1].kind)))return!1;let a=s[1];return a.kind!=="source-siblings"||Array.isArray(a.siblingEntryIndexes)&&a.siblingEntryIndexes.length>=2&&a.siblingEntryIndexes.every(u=>l(u)&&u<e.entries.length)&&a.siblingEntryIndexes.includes(s[0])}))&&(i===void 0||Array.isArray(i)&&i.every(s=>Array.isArray(s)&&s.length===2&&l(s[0])&&s[0]<e.entries.length&&S(s[1])))}function S(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function U(t){return!S(t)||typeof t.routeId!="string"?!1:t.effectiveTemplateId===void 0||typeof t.effectiveTemplateId=="string"}function l(t){return typeof t=="number"&&Number.isInteger(t)&&t>=0}var m=class t{constructor(){}static parseMessage(e,n={}){let o=JSON.parse(e);if(!t.isMessage(o,n))throw new Error("Invalid site edit bridge message");return o}static stringifyMessage(e){return JSON.stringify(e)}static extractRequestInfo(e){if(h(e)&&h(e.payload)){let n=typeof e.payload.id=="string"?e.payload.id:"unknown",o=this.isRequestKind(e.payload.kind)?e.payload.kind:"get-document";return{id:n,kind:o}}return{id:"unknown",kind:"get-document"}}static isRequestKind(e){return e==="initialize-session"||e==="get-document"||e==="get-history-status"||e==="get-style-context"||e==="get-object-edit-context"||e==="get-class-name-source"||e==="get-source-tree"||e==="get-source-file"||e==="resolve-source-location"||e==="execute"||e==="undo"||e==="redo"}static isMessage(e,n={}){return!h(e)||typeof e.type!="string"?!1:e.type==="request"?W(e.payload,n):e.type==="response"||e.type==="error"?h(e.payload)&&typeof e.payload.id=="string":e.type==="event"?h(e.payload)&&h(e.payload.event):e.type==="auth"?h(e.payload)&&typeof e.payload.key=="string":e.type==="auth-ok"&&h(e.payload)&&e.payload.ok===!0}};function W(t,e){if(!h(t)||typeof t.id!="string"||!m.isRequestKind(t.kind))return!1;let n=k(t.composition);switch(t.kind){case"initialize-session":return n&&(t.mutationContext===void 0||E(t.mutationContext));case"get-document":case"get-style-context":return n;case"get-object-edit-context":return typeof t.key=="string"&&n&&$(t.selectionRef);case"get-class-name-source":case"resolve-source-location":return typeof t.key=="string"&&n;case"get-history-status":return n;case"get-source-tree":return n;case"get-source-file":return typeof t.path=="string"&&n;case"execute":return n&&z(t.request)&&(t.request.mutationContext===void 0||E(t.request.mutationContext))&&(e.validateOperationRequest?.(t.request)??!0);case"undo":case"redo":return n&&t.mutationContext===void 0||n&&E(t.mutationContext)}}function $(t){if(t===void 0)return!0;if(!h(t)||typeof t.key!="string"||t.key.length===0)return!1;let e=t.instanceIndex,n=t.instanceCount;return e!==void 0&&(typeof e!="number"||!Number.isInteger(e)||e<0)||n!==void 0&&(typeof n!="number"||!Number.isInteger(n)||n<=0)||typeof e=="number"&&typeof n=="number"&&e>=n?!1:Object.keys(t).every(o=>o==="key"||o==="instanceIndex"||o==="instanceCount")}function z(t){return h(t)&&typeof t.id=="string"&&typeof t.siteId=="string"&&typeof t.baseSnapshotId=="string"&&k(t.composition)&&typeof t.kind=="string"&&h(t.target)&&(t.target.kind!=="route"||k(t.target.composition))&&typeof t.documentVersion=="number"&&Number.isInteger(t.documentVersion)&&t.documentVersion>=0&&h(t.params)}function k(t){return h(t)&&typeof t.routeId=="string"&&t.routeId.length>0&&(t.templateId===void 0||typeof t.templateId=="string"&&t.templateId.length>0)&&Object.keys(t).every(e=>e==="routeId"||e==="templateId")}function h(t){return typeof t=="object"&&t!==null}function E(t){return h(t)&&typeof t.editingSessionId=="string"&&t.editingSessionId.length>0&&typeof t.lockId=="string"&&t.lockId.length>0&&typeof t.ownerId=="string"&&t.ownerId.length>0&&typeof t.leaseAssertion=="string"&&t.leaseAssertion.length>0}var L="vcp:designer:trace",V="designer_trace",M="__VCP_DESIGNER_TRACE__";var J=/(authorization|cookie|token|secret|providerTrace|headers?|sourceCode|rawSource|fullSource)/i;function G(t=globalThis){let e=t;try{if(e.localStorage?.getItem(L)==="1")return!0}catch{}try{let n=e.location?.search??"";return new URLSearchParams(n).get(V)==="1"}catch{return!1}}function f(t,e={},n=globalThis){if(!G(n))return;let o={type:t,timestamp:Date.now(),payload:Q(e)},i=n,r=i[M]??[];r.push(o),r.length>1e3&&r.splice(0,r.length-1e3),i[M]=r;let c=n.console?.debug;o.payload.diagnosticOnly!==!0&&typeof c=="function"&&c.call(n.console,"[designer-trace]",o)}function Q(t){return q(t,0)}function q(t,e){if(e>4)return"[truncated]";if(Array.isArray(t))return t.map(o=>q(o,e+1));if(!t||typeof t!="object")return t;let n={};for(let[o,i]of Object.entries(t)){if(J.test(o)){n[o]="[redacted]";continue}n[o]=q(i,e+1)}return n}var v=class{constructor(e){this.options=e,this.socket=null,this.connectPromise=null,this.connectAttempt=null,this.connectionState="idle",this.intentionalClose=!1,this.sequence=0,this.pending=new Map,this.listeners=new Set,this.connectionStatusListeners=new Set}connect(){return this.socket?.readyState===T&&this.connectionState==="open"?(this.setConnectionState("open"),Promise.resolve()):this.connectPromise?this.connectPromise:(this.intentionalClose=!1,this.setConnectionState("connecting"),this.connectPromise=new Promise((e,n)=>{let o;try{o=this.createSocket(this.options.url)}catch(s){let a=I(s,"WebSocket failed");this.socket=null,this.connectAttempt=null,this.connectPromise=null,this.setConnectionState("failed",a.message),n(a);return}let i={socket:o,settled:!1,reject:n};this.connectAttempt=i,this.socket=o;let r=()=>{this.socket!==o||this.connectAttempt!==i||(i.settled=!0,this.connectAttempt=null,this.connectPromise=null,this.setConnectionState("open"),e())},c=(s,a)=>{this.cleanupSocket(o,s,a)};o.onopen=()=>{if(!(this.socket!==o||this.connectAttempt!==i)){if(this.options.authKey){try{o.send(m.stringifyMessage({type:"auth",payload:{key:this.options.authKey}}))}catch(s){c(I(s,"WebSocket auth failed"),"failed")}return}r()}},o.onerror=s=>{if(this.socket!==o)return;let a=I(s,"WebSocket failed");c(a,"failed")},o.onmessage=s=>{if(this.socket===o){if(this.options.authKey&&this.connectAttempt===i&&!i.settled){this.handleAuthHandshakeMessage(s.data,o,i,()=>{r()});return}this.handleMessage(s.data)}},o.onclose=s=>{if(this.socket!==o)return;let a=this.intentionalClose,u=new Error(X(s,{intentional:a}));c(u,a?"closed":"failed")}}),this.connectPromise)}disconnect(){this.intentionalClose=!0,this.setConnectionState("closing");let e=this.socket;if(!e){this.rejectAll(new Error("WebSocket disconnected")),this.connectAttempt=null,this.connectPromise=null,this.setConnectionState("closed");return}this.cleanupSocket(e,new Error("WebSocket disconnected"),"closed")}getConnectionState(){return this.connectionState}subscribeConnectionStatus(e){return this.connectionStatusListeners.add(e),e({state:this.connectionState}),()=>{this.connectionStatusListeners.delete(e)}}getDocument(e){let n=this.selector(e);return this.request("get-document",{composition:n})}async initializeSession(e){let n=this.selector(e.composition);return await this.request("initialize-session",{composition:n,...e.mutationContext?{mutationContext:e.mutationContext}:{}})}getHistoryStatus(e){return this.request("get-history-status",{composition:this.selector(e)})}getStyleContext(e){let n=this.selector(e);return this.request("get-style-context",{composition:n})}getObjectEditContext(e,n,o){let i=this.selector(n);return this.request("get-object-edit-context",{key:e,composition:i,...o?{selectionRef:o}:{}})}getClassNameSource(e,n){let o=this.selector(n);return this.request("get-class-name-source",{key:e,composition:o})}getSourceTree(e){return this.request("get-source-tree",{composition:this.selector(e)})}getSourceFile(e){return this.request("get-source-file",{path:e.path,composition:this.selector(e.composition)})}resolveSourceLocation(e){return this.request("resolve-source-location",{key:e.key,composition:this.selector(e.composition)})}execute(e,n){let o=x(e),i={...e,composition:g(o)};return this.request("execute",{request:i})}undo(e,n){return this.request("undo",{composition:this.selector(e)})}redo(e,n){return this.request("redo",{composition:this.selector(e)})}subscribe(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}selector(e){return g(e)}request(e,n){let o=this.socket;if(!o||o.readyState!==T||this.connectionState!=="open")return Promise.reject(new Error(`WebSocket is not open (state: ${this.connectionState}, readyState: ${o?.readyState??"none"})`));let i=`${e}-${this.sequence+=1}`,r=oe(i,e,n);return f("bridge.request",{id:i,kind:e,routeId:typeof n.routeId=="string"?n.routeId:null,key:typeof n.key=="string"?n.key:null,operationKind:N(n.request,"kind"),documentVersion:N(n.request,"documentVersion")}),new Promise((c,s)=>{let a=this.resolveRequestTimeoutMs(e),u=a>0?setTimeout(()=>{let d=this.pending.get(i);d&&(this.pending.delete(i),f("bridge.response",{id:i,kind:e,ok:!1,timedOut:!0}),d.reject(new Error(`Bridge request timed out after ${a}ms: ${e}`)))},a):null;u?.unref?.(),this.pending.set(i,{kind:e,timeout:u,resolve:d=>c(d),reject:s});try{o.send(m.stringifyMessage(r))}catch(d){let p=I(d,"WebSocket send failed");this.clearPendingRequest(i),s(p),this.cleanupSocket(o,p,"failed")}})}handleAuthHandshakeMessage(e,n,o,i){try{if(m.parseMessage(e).type==="auth-ok"){i();return}throw new Error("Bridge authentication failed")}catch(r){let c=I(r,"Bridge authentication failed");this.connectAttempt===o&&this.cleanupSocket(n,c,"failed")}}handleMessage(e){let n=m.parseMessage(e);if(n.type==="event"){for(let i of this.listeners)i(n.payload.event);return}if(n.type!=="response"&&n.type!=="error")return;let o=this.pending.get(n.payload.id);if(o){if(this.clearPendingRequest(n.payload.id),n.type==="error"){f("bridge.response",{id:n.payload.id,kind:o.kind,ok:!1});let i=new Error(n.payload.message);n.payload.code&&(i.code=n.payload.code),o.reject(i);return}f("bridge.response",{id:n.payload.id,kind:o.kind,ok:!0,resultVersion:ee(n.payload.result)}),o.resolve(o.kind==="get-document"?{...n.payload.result,data:j(n.payload.result.data,n.payload.result.composition)}:o.kind==="initialize-session"?te(n.payload.result):n.payload.result)}}rejectAll(e){for(let[n,o]of[...this.pending])this.clearPendingRequest(n),o.reject(e)}clearPendingRequest(e){let n=this.pending.get(e);n&&(n.timeout&&clearTimeout(n.timeout),this.pending.delete(e))}resolveRequestTimeoutMs(e){let n=this.options.requestTimeoutMsByKind?.[e];return typeof n=="number"?Math.max(0,n):typeof this.options.requestTimeoutMs=="number"?Math.max(0,this.options.requestTimeoutMs):Z[e]??Y}cleanupSocket(e,n,o){if(this.socket===e&&(this.socket=null),this.connectAttempt?.socket===e){let i=this.connectAttempt;this.connectAttempt=null,i.settled||(i.settled=!0,i.reject(n))}this.connectPromise=null,this.rejectAll(n),this.setConnectionState(o,n.message),e.onopen=null,e.onmessage=null,e.onerror=null,e.onclose=null;try{(e.readyState===H||e.readyState===T)&&e.close()}catch{}}setConnectionState(e,n){if(this.connectionState===e&&!n)return;this.connectionState=e;let o={state:e,...n?{message:n}:{}};this.options.onConnectionStatus?.(o);for(let i of this.connectionStatusListeners)i(o)}createSocket(e){if(this.options.createSocket)return this.options.createSocket(e);if(typeof WebSocket>"u")throw new Error("Site edit preview bridge requires WebSocket");return new WebSocket(e)}},H=0,T=1,Y=15e3,Z={"get-source-tree":1e4,"get-source-file":1e4,"resolve-source-location":1e4,execute:6e4,undo:2e4,redo:2e4};function I(t,e){return t instanceof Error?t:new Error(e)}function X(t,e){return e.intentional?"WebSocket disconnected":t?.code===1008?t.reason?`Bridge session authentication failed: ${t.reason}`:"Bridge session authentication failed":t?.reason?`WebSocket closed: ${t.reason}`:typeof t?.code=="number"&&t.code!==1005?`WebSocket closed with code ${t.code}`:"WebSocket closed"}function N(t,e){if(!t||typeof t!="object")return null;let o=t[e];return typeof o=="string"||typeof o=="number"?o:null}function ee(t){if(!t||typeof t!="object")return null;let e=t,n=e.data?.resultVersion??e.data?.version??null;return typeof n=="number"?n:null}function pe(t){let e="composition"in t?g(t.composition):g({routeId:t.routeId});return new R({composition:e,initialDocument:t.initialDocument,client:t.client})}var R=class{constructor(e){this.params=e,this.serverConfirmedComposition=null,this.refreshInFlight=null,this.objectGeneration=0,this.styleGeneration=0,this.editContextCache=new Map,this.editContextInFlight=new Map,this.classNameSourceCache=new Map,this.classNameSourceInFlight=new Map,this.styleContextCache=new Map,this.styleContextInFlight=new Map,this.snapshotIdentityStale=!1,this.composition=g(e.composition);let n=e.initialDocument.composition.effectiveTemplateId;if(n!==void 0&&(this.composition.templateId===void 0||this.composition.templateId!==n))throw new Error(`Site edit bridge requires a matching templateId for initial document composition ${JSON.stringify(e.initialDocument.composition)}`);this.currentDocument=e.initialDocument,this.observedDocumentVersion=e.initialDocument.version,this.sessionInitialized=!K(e.initialDocument),this.activeCompositionContext=this.sessionInitialized?{...e.initialDocument.composition}:null}async getDocument(e){this.requireBoundComposition(e);let n=K(this.currentDocument)||this.snapshotIdentityStale;return(n||this.currentDocument.version<this.observedDocumentVersion)&&(this.currentDocument=await this.refreshSnapshot(n?void 0:this.observedDocumentVersion,"get-document"),this.snapshotIdentityStale=!1,this.sessionInitialized=!0),{ok:!0,data:this.currentDocument}}async initializeSession(e){let n=this.requireBoundComposition(e.composition);if(!this.params.client.initializeSession)throw new Error("Site edit bridge client does not support initialize-session");let o=await this.params.client.initializeSession({...e,composition:n});return this.currentDocument=o.data.document,this.observedDocumentVersion=o.data.document.version,this.activeCompositionContext={...o.composition},this.rememberServerConfirmedComposition(o.composition),this.sessionInitialized=!0,this.clearObjectCaches(),o}async getHistoryStatus(e){return this.params.client.getHistoryStatus(this.requireBoundComposition(e))}async getStyleContext(e){let n=this.requireBoundComposition(e),o=C(n),i=this.styleContextCache.get(o);if(i?.generation===this.styleGeneration)return{ok:!0,data:i.value};let r=this.styleContextInFlight.get(o);if(r?.generation===this.styleGeneration)return r.request;let c=this.styleGeneration,s=this.params.client.getStyleContext(n).then(a=>(this.styleGeneration===c&&this.styleContextCache.set(o,{generation:c,value:a.data}),a)).finally(()=>{this.styleContextInFlight.get(o)?.request===s&&this.styleContextInFlight.delete(o)});return this.styleContextInFlight.set(o,{generation:c,request:s}),s}async ensureDocumentVersion(e,n){this.requireBoundComposition(e);let o=await this.refreshSnapshot(n,"ensure-version");if(o.version<n)throw new Error(`Document refresh returned version ${o.version}, expected at least ${n}`);return{ok:!0,data:o}}async acknowledgeDocumentVersion(e,n){if(this.requireBoundComposition(e),n>this.currentDocument.version){if(this.currentDocument.pageComposition.status==="supported"){let o=await this.refreshSnapshot(n,"ensure-version");if(o.version<n)throw new Error(`Document refresh returned version ${o.version}, expected at least ${n}`);return{ok:!0,data:o}}this.currentDocument={...this.currentDocument,version:n},this.clearObjectCaches({preserveStyleContext:!0})}return this.observedDocumentVersion=Math.max(this.observedDocumentVersion,n),{ok:!0,data:this.currentDocument}}async getObjectEditContext(e,n,o){let i=this.requireBoundComposition(n),r=this.objectCacheKey(e,i,o),c=this.editContextCache.get(r);if(c)return{ok:!0,data:c};let s=this.editContextInFlight.get(r);if(s)return s;let a=this.objectGeneration,u=this.params.client.getObjectEditContext(e,i,...o?[o]:[]).then(d=>(this.objectGeneration===a&&this.editContextCache.set(r,d.data),d)).finally(()=>{this.editContextInFlight.get(r)===u&&this.editContextInFlight.delete(r)});return this.editContextInFlight.set(r,u),u}async getClassNameSource(e,n){let o=this.requireBoundComposition(n),i=this.objectCacheKey(e,o),r=this.classNameSourceCache.get(i);if(r)return r;let c=this.classNameSourceInFlight.get(i);if(c)return c;let s=this.objectGeneration,a=this.params.client.getClassNameSource(e,o).then(u=>(this.objectGeneration===s&&this.classNameSourceCache.set(i,u),u)).finally(()=>{this.classNameSourceInFlight.get(i)===a&&this.classNameSourceInFlight.delete(i)});return this.classNameSourceInFlight.set(i,a),a}async getSourceTree(e){return this.params.client.getSourceTree(this.requireBoundComposition(e))}async getSourceFile(e){return this.params.client.getSourceFile({path:e.path,composition:this.requireBoundComposition(e.composition)})}async resolveSourceLocation(e){return this.params.client.resolveSourceLocation({key:e.key,composition:this.requireBoundComposition(e.composition)})}async execute(e,n){let o=x(e);o&&this.composition.templateId!==void 0&&this.requireBoundComposition(o);let i={...e,composition:o??this.composition};return this.params.client.execute(i)}async undo(e,n){return this.params.client.undo(this.requireBoundComposition(e))}async redo(e,n){return this.params.client.redo(this.requireBoundComposition(e))}subscribe(e){return this.params.client.subscribe(n=>{if(n.type==="site-edit.snapshot.changed"&&this.sessionInitialized&&this.isActiveComposition(n.composition)){this.snapshotIdentityStale=!0,this.clearObjectCaches(),e(n);return}if(n.type==="site-edit.document.changed"&&this.sessionInitialized&&this.isActiveComposition(n.composition)){this.observedDocumentVersion=Math.max(this.observedDocumentVersion,n.version),n.version>this.currentDocument.version&&this.clearObjectCaches(),e(n);return}e(n)})}async refreshSnapshot(e,n="ensure-version"){if(typeof e=="number"&&this.currentDocument.version>=e)return f("bridge.document-refresh",{composition:this.composition,routeId:this.composition.routeId,minVersion:e,currentVersion:this.currentDocument.version,deduped:!0,skipped:!0,source:n}),this.currentDocument;let o=C(this.composition),i=this.refreshInFlight;if(i?.compositionKey===o){f("bridge.document-refresh",{composition:this.composition,routeId:this.composition.routeId,minVersion:e,currentVersion:this.currentDocument.version,deduped:!0,source:n});let c=await i.request;if(typeof e!="number"||c.version>=e||this.currentDocument.version>=e)return this.currentDocument}f("bridge.document-refresh",{composition:this.composition,routeId:this.composition.routeId,minVersion:e,currentVersion:this.currentDocument.version,deduped:!1,source:n});let r=this.params.client.getDocument(this.composition).then(c=>(this.currentDocument=c.data,this.activeCompositionContext={...c.data.composition},this.rememberServerConfirmedComposition(c.data.composition),this.observedDocumentVersion=Math.max(this.observedDocumentVersion,c.data.version),this.clearObjectCaches(),this.currentDocument));this.refreshInFlight={compositionKey:o,request:r};try{return await r}finally{this.refreshInFlight?.request===r&&(this.refreshInFlight=null)}}clearObjectCaches(e){this.objectGeneration+=1,this.editContextCache.clear(),this.editContextInFlight.clear(),this.classNameSourceCache.clear(),this.classNameSourceInFlight.clear(),!e?.preserveStyleContext&&(this.styleGeneration+=1,this.styleContextCache.clear(),this.styleContextInFlight.clear())}objectCacheKey(e,n,o){return`${C(n)}\0${e}\0${ne(o)}`}rememberServerConfirmedComposition(e){!e||typeof e.routeId!="string"||(this.serverConfirmedComposition={...e})}isAcceptedComposition(e){if(C(e)===C(this.composition))return!0;let n=this.serverConfirmedComposition;return n!==null&&b(n)===b(B(e))}requireBoundComposition(e){let n=e===void 0?this.composition:g(e);if(!this.isAcceptedComposition(n))throw new Error(`Site edit bridge is bound to composition ${JSON.stringify(this.composition)}, received ${JSON.stringify(n)}`);return g(n)}isActiveComposition(e){let n=this.activeCompositionContext??B(this.composition);return b(e)===b(n)}};function K(t){return t.version===0&&t.entries.length===0}function te(t){let e=t;return{...e,data:{...e.data,document:j(e.data.document,e.composition)}}}function j(t,e){let n=t,o=O(n.routeId?n:{...n,routeId:e?.routeId??n.composition?.routeId});return e?{...o,composition:e}:o}function g(t){if(t&&typeof t=="object"&&typeof t.routeId=="string"){let e="effectiveTemplateId"in t?t.effectiveTemplateId:"templateId"in t?t.templateId:void 0;return{routeId:t.routeId,...typeof e=="string"?{templateId:e}:{}}}throw new Error("SITE_EDIT_COMPOSITION_SESSION_REQUIRED: a composition selector is required")}function C(t){return JSON.stringify([t.routeId,t.templateId??null])}function ne(t){return t?JSON.stringify([t.key,t.instanceIndex??null,t.instanceCount??null]):""}function b(t){return JSON.stringify([t.routeId,t.effectiveTemplateId??null])}function B(t){return{routeId:t.routeId,...t.templateId?{effectiveTemplateId:t.templateId}:{}}}function x(t){if(t&&typeof t=="object"){let e=t;if(e.composition&&typeof e.composition=="object"){let n=e.composition;if(typeof n.routeId=="string")return{routeId:n.routeId,...typeof n.templateId=="string"?{templateId:n.templateId}:{}}}}}function oe(t,e,n){let o=g(e==="execute"?x(n.request):n.composition),i={id:t,kind:e,composition:o};switch(e){case"initialize-session":case"get-document":case"get-history-status":case"get-style-context":case"get-source-tree":case"undo":case"redo":return{type:"request",payload:{...i,...n.mutationContext?{mutationContext:n.mutationContext}:{}}};case"get-object-edit-context":return{type:"request",payload:{...i,key:String(n.key),...n.selectionRef?{selectionRef:n.selectionRef}:{}}};case"get-class-name-source":case"resolve-source-location":return{type:"request",payload:{...i,key:String(n.key)}};case"get-source-file":return{type:"request",payload:{...i,path:String(n.path)}};case"execute":return{type:"request",payload:{...i,request:{...n.request,composition:x(n.request)??o}}}}}export{v as SiteEditWebSocketClient,pe as createSiteEditBridge};
1
+ function _(t){if(!P(t)){if(t.encoding==="segment-trie-v1")throw new Error("Invalid compact render document");return t}let e=new Map,n=t.pageComposition.status==="supported"?t.pageComposition.placementUnitKeys:[],o=new Map(t.dynamicDataSummaries??[]),i=new Map(t.pageCompositionActionScopes??[]),r=c=>{let s=e.get(c);if(s)return s;let a=t.nodes[c];if(!a)throw new Error(`Missing compact document node ${c}`);let[u,d]=a,p=t.tokens[d];if(typeof p!="string")throw new Error(`Missing compact document token ${d}`);let y=`${u===null?"":r(u)}${p}`;return e.set(c,y),y};return{siteId:t.siteId,snapshotId:t.snapshotId,composition:{...t.composition},routeId:t.composition.routeId,version:t.version,pageComposition:t.pageComposition,entries:t.entries.map((c,s)=>{let[a,u,d]=c,p=d===void 0?void 0:n[d];if(d!==void 0&&!p)throw new Error(`Missing page composition unit ${d}`);let y=t.entryParentNodeIds?.[s],w=i.get(s),D=w?.kind==="source-siblings"?{kind:"source-siblings",siblingKeys:w.siblingEntryIndexes.map(A=>{let O=t.entries[A];if(!O)throw new Error(`Missing source sibling entry ${A}`);return r(O[0])})}:w;return{key:r(a),...t.entryParentNodeIds?{parentKey:y===null?null:r(y)}:{},...p?{pageCompositionUnitKey:p}:{},...D?{pageCompositionActionScope:D}:{},operationSummary:F(u),...o.get(s)?{dynamicDataSummary:o.get(s)}:{}}})}}function F(t){return{canUpdateText:(t&1)!==0,canInsertChild:(t&2)!==0,canMove:(t&4)!==0,canRemove:(t&8)!==0}}function P(t){if(typeof t!="object"||t===null)return!1;let e=t;if(e.encoding!=="segment-trie-v1"||typeof e.siteId!="string"||typeof e.snapshotId!="string"||!U(e.composition)||typeof e.routeId!="string"||e.routeId!==e.composition.routeId||!Number.isInteger(e.version)||e.version<0||!b(e.pageComposition)||!Array.isArray(e.tokens)||!e.tokens.every(s=>typeof s=="string")||!Array.isArray(e.nodes)||!Array.isArray(e.entries))return!1;let n=e.nodes;if(!n.every((s,a)=>Array.isArray(s)&&s.length===2&&(s[0]===null||l(s[0])&&s[0]<a)&&l(s[1])&&s[1]<e.tokens.length)||!e.entries.every(s=>Array.isArray(s)&&(s.length===2||s.length===3)&&l(s[0])&&s[0]<n.length&&l(s[1])&&s[1]<=15&&(s.length===2||l(s[2]))))return!1;let o=e.entryParentNodeIds;if(o!==void 0&&(!Array.isArray(o)||o.length!==e.entries.length||!o.every(s=>s===null||l(s)&&s<n.length)))return!1;let i=e.dynamicDataSummaries,r=e.pageCompositionActionScopes;return(r===void 0||Array.isArray(r)&&r.every(s=>{if(!Array.isArray(s)||s.length!==2||!l(s[0])||s[0]>=e.entries.length||!b(s[1])||!["route-unit","source-siblings","unavailable"].includes(String(s[1].kind)))return!1;let a=s[1];return a.kind!=="source-siblings"||Array.isArray(a.siblingEntryIndexes)&&a.siblingEntryIndexes.length>=2&&a.siblingEntryIndexes.every(u=>l(u)&&u<e.entries.length)&&a.siblingEntryIndexes.includes(s[0])}))&&(i===void 0||Array.isArray(i)&&i.every(s=>Array.isArray(s)&&s.length===2&&l(s[0])&&s[0]<e.entries.length&&b(s[1])))}function b(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function U(t){return!b(t)||typeof t.routeId!="string"?!1:t.effectiveTemplateId===void 0||typeof t.effectiveTemplateId=="string"}function l(t){return typeof t=="number"&&Number.isInteger(t)&&t>=0}var f=class t{constructor(){}static parseMessage(e,n={}){let o=JSON.parse(e);if(!t.isMessage(o,n))throw new Error("Invalid site edit bridge message");return o}static stringifyMessage(e){return JSON.stringify(e)}static extractRequestInfo(e){if(h(e)&&h(e.payload)){let n=typeof e.payload.id=="string"?e.payload.id:"unknown",o=this.isRequestKind(e.payload.kind)?e.payload.kind:"get-document";return{id:n,kind:o}}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!h(e)||typeof e.type!="string"?!1:e.type==="request"?W(e.payload,n):e.type==="response"||e.type==="error"?h(e.payload)&&typeof e.payload.id=="string":e.type==="event"?h(e.payload)&&h(e.payload.event):e.type==="auth"?h(e.payload)&&typeof e.payload.key=="string":e.type==="auth-ok"&&h(e.payload)&&e.payload.ok===!0}};function W(t,e){if(!h(t)||typeof t.id!="string"||!f.isRequestKind(t.kind))return!1;let n=E(t.composition);switch(t.kind){case"initialize-session":return n&&(t.mutationContext===void 0||k(t.mutationContext));case"get-document":case"get-style-context":return n;case"get-object-edit-context":return typeof t.key=="string"&&n&&$(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&&z(t.request)&&(t.request.mutationContext===void 0||k(t.request.mutationContext))&&(e.validateOperationRequest?.(t.request)??!0);case"undo":case"redo":return n&&t.mutationContext===void 0||n&&k(t.mutationContext)}}function $(t){if(t===void 0)return!0;if(!h(t)||typeof t.key!="string"||t.key.length===0)return!1;let e=t.instanceIndex,n=t.instanceCount;return e!==void 0&&(typeof e!="number"||!Number.isInteger(e)||e<0)||n!==void 0&&(typeof n!="number"||!Number.isInteger(n)||n<=0)||typeof e=="number"&&typeof n=="number"&&e>=n?!1:Object.keys(t).every(o=>o==="key"||o==="instanceIndex"||o==="instanceCount")}function z(t){return h(t)&&typeof t.id=="string"&&typeof t.siteId=="string"&&typeof t.baseSnapshotId=="string"&&E(t.composition)&&typeof t.kind=="string"&&h(t.target)&&(t.target.kind!=="route"||E(t.target.composition))&&typeof t.documentVersion=="number"&&Number.isInteger(t.documentVersion)&&t.documentVersion>=0&&h(t.params)}function E(t){return h(t)&&typeof t.routeId=="string"&&t.routeId.length>0&&(t.templateId===void 0||typeof t.templateId=="string"&&t.templateId.length>0)&&Object.keys(t).every(e=>e==="routeId"||e==="templateId")}function h(t){return typeof t=="object"&&t!==null}function k(t){return h(t)&&typeof t.editingSessionId=="string"&&t.editingSessionId.length>0&&typeof t.lockId=="string"&&t.lockId.length>0&&typeof t.ownerId=="string"&&t.ownerId.length>0&&typeof t.leaseAssertion=="string"&&t.leaseAssertion.length>0}var L="vcp:designer:trace",V="designer_trace",M="__VCP_DESIGNER_TRACE__";var J=/(authorization|cookie|token|secret|providerTrace|headers?|sourceCode|rawSource|fullSource)/i;function G(t=globalThis){let e=t;try{if(e.localStorage?.getItem(L)==="1")return!0}catch{}try{let n=e.location?.search??"";return new URLSearchParams(n).get(V)==="1"}catch{return!1}}function g(t,e={},n=globalThis){if(!G(n))return;let o={type:t,timestamp:Date.now(),payload:Q(e)},i=n,r=i[M]??[];r.push(o),r.length>1e3&&r.splice(0,r.length-1e3),i[M]=r;let c=n.console?.debug;o.payload.diagnosticOnly!==!0&&typeof c=="function"&&c.call(n.console,"[designer-trace]",o)}function Q(t){return q(t,0)}function q(t,e){if(e>4)return"[truncated]";if(Array.isArray(t))return t.map(o=>q(o,e+1));if(!t||typeof t!="object")return t;let n={};for(let[o,i]of Object.entries(t)){if(J.test(o)){n[o]="[redacted]";continue}n[o]=q(i,e+1)}return n}var v=class{constructor(e){this.options=e,this.socket=null,this.connectPromise=null,this.connectAttempt=null,this.connectionState="idle",this.intentionalClose=!1,this.sequence=0,this.pending=new Map,this.listeners=new Set,this.connectionStatusListeners=new Set}connect(){return this.socket?.readyState===R&&this.connectionState==="open"?(this.setConnectionState("open"),Promise.resolve()):this.connectPromise?this.connectPromise:(this.intentionalClose=!1,this.setConnectionState("connecting"),this.connectPromise=new Promise((e,n)=>{let o;try{o=this.createSocket(this.options.url)}catch(s){let a=I(s,"WebSocket failed");this.socket=null,this.connectAttempt=null,this.connectPromise=null,this.setConnectionState("failed",a.message),n(a);return}let i={socket:o,settled:!1,reject:n};this.connectAttempt=i,this.socket=o;let r=()=>{this.socket!==o||this.connectAttempt!==i||(i.settled=!0,this.connectAttempt=null,this.connectPromise=null,this.setConnectionState("open"),e())},c=(s,a)=>{this.cleanupSocket(o,s,a)};o.onopen=()=>{if(!(this.socket!==o||this.connectAttempt!==i)){if(this.options.authKey){try{o.send(f.stringifyMessage({type:"auth",payload:{key:this.options.authKey}}))}catch(s){c(I(s,"WebSocket auth failed"),"failed")}return}r()}},o.onerror=s=>{if(this.socket!==o)return;let a=I(s,"WebSocket failed");c(a,"failed")},o.onmessage=s=>{if(this.socket===o){if(this.options.authKey&&this.connectAttempt===i&&!i.settled){this.handleAuthHandshakeMessage(s.data,o,i,()=>{r()});return}this.handleMessage(s.data)}},o.onclose=s=>{if(this.socket!==o)return;let a=this.intentionalClose,u=new Error(X(s,{intentional:a}));c(u,a?"closed":"failed")}}),this.connectPromise)}disconnect(){this.intentionalClose=!0,this.setConnectionState("closing");let e=this.socket;if(!e){this.rejectAll(new Error("WebSocket disconnected")),this.connectAttempt=null,this.connectPromise=null,this.setConnectionState("closed");return}this.cleanupSocket(e,new Error("WebSocket disconnected"),"closed")}getConnectionState(){return this.connectionState}subscribeConnectionStatus(e){return this.connectionStatusListeners.add(e),e({state:this.connectionState}),()=>{this.connectionStatusListeners.delete(e)}}getDocument(e){let n=this.selector(e);return this.request("get-document",{composition:n})}async initializeSession(e){let n=this.selector(e.composition);return await this.request("initialize-session",{composition:n,...e.mutationContext?{mutationContext:e.mutationContext}:{}})}getHistoryStatus(e){return this.request("get-history-status",{composition:this.selector(e)})}getStyleContext(e){let n=this.selector(e);return this.request("get-style-context",{composition:n})}getObjectEditContext(e,n,o){let i=this.selector(n);return this.request("get-object-edit-context",{key:e,composition:i,...o?{selectionRef:o}:{}})}getClassNameSource(e,n){let o=this.selector(n);return this.request("get-class-name-source",{key:e,composition:o})}getSourceTree(e){return this.request("get-source-tree",{composition:this.selector(e)})}getSourceFile(e){return this.request("get-source-file",{path:e.path,composition:this.selector(e.composition)})}resolveSourceLocation(e){return this.request("resolve-source-location",{key:e.key,composition:this.selector(e.composition)})}execute(e,n){let o=S(e),i={...e,composition:m(o)};return this.request("execute",{request:i})}getOperationResult(e){return this.request("get-operation-result",{request:e,composition:m(S(e))})}undo(e,n){return this.request("undo",{composition:this.selector(e)})}redo(e,n){return this.request("redo",{composition:this.selector(e)})}subscribe(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}selector(e){return m(e)}request(e,n){let o=this.socket;if(!o||o.readyState!==R||this.connectionState!=="open")return Promise.reject(new Error(`WebSocket is not open (state: ${this.connectionState}, readyState: ${o?.readyState??"none"})`));let i=`${e}-${this.sequence+=1}`,r=oe(i,e,n);return g("bridge.request",{id:i,kind:e,routeId:typeof n.routeId=="string"?n.routeId:null,key:typeof n.key=="string"?n.key:null,operationKind:N(n.request,"kind"),documentVersion:N(n.request,"documentVersion")}),new Promise((c,s)=>{let a=this.resolveRequestTimeoutMs(e),u=a>0?setTimeout(()=>{let d=this.pending.get(i);d&&(this.pending.delete(i),g("bridge.response",{id:i,kind:e,ok:!1,timedOut:!0}),d.reject(new Error(`Bridge request timed out after ${a}ms: ${e}`)))},a):null;u?.unref?.(),this.pending.set(i,{kind:e,timeout:u,resolve:d=>c(d),reject:s});try{o.send(f.stringifyMessage(r))}catch(d){let p=I(d,"WebSocket send failed");this.clearPendingRequest(i),s(p),this.cleanupSocket(o,p,"failed")}})}handleAuthHandshakeMessage(e,n,o,i){try{if(f.parseMessage(e).type==="auth-ok"){i();return}throw new Error("Bridge authentication failed")}catch(r){let c=I(r,"Bridge authentication failed");this.connectAttempt===o&&this.cleanupSocket(n,c,"failed")}}handleMessage(e){let n=f.parseMessage(e);if(n.type==="event"){for(let i of this.listeners)i(n.payload.event);return}if(n.type!=="response"&&n.type!=="error")return;let o=this.pending.get(n.payload.id);if(o){if(this.clearPendingRequest(n.payload.id),n.type==="error"){g("bridge.response",{id:n.payload.id,kind:o.kind,ok:!1});let i=new Error(n.payload.message);n.payload.code&&(i.code=n.payload.code),o.reject(i);return}g("bridge.response",{id:n.payload.id,kind:o.kind,ok:!0,resultVersion:ee(n.payload.result)}),o.resolve(o.kind==="get-document"?{...n.payload.result,data:j(n.payload.result.data,n.payload.result.composition)}:o.kind==="initialize-session"?te(n.payload.result):n.payload.result)}}rejectAll(e){for(let[n,o]of[...this.pending])this.clearPendingRequest(n),o.reject(e)}clearPendingRequest(e){let n=this.pending.get(e);n&&(n.timeout&&clearTimeout(n.timeout),this.pending.delete(e))}resolveRequestTimeoutMs(e){let n=this.options.requestTimeoutMsByKind?.[e];return typeof n=="number"?Math.max(0,n):typeof this.options.requestTimeoutMs=="number"?Math.max(0,this.options.requestTimeoutMs):Z[e]??Y}cleanupSocket(e,n,o){if(this.socket===e&&(this.socket=null),this.connectAttempt?.socket===e){let i=this.connectAttempt;this.connectAttempt=null,i.settled||(i.settled=!0,i.reject(n))}this.connectPromise=null,this.rejectAll(n),this.setConnectionState(o,n.message),e.onopen=null,e.onmessage=null,e.onerror=null,e.onclose=null;try{(e.readyState===H||e.readyState===R)&&e.close()}catch{}}setConnectionState(e,n){if(this.connectionState===e&&!n)return;this.connectionState=e;let o={state:e,...n?{message:n}:{}};this.options.onConnectionStatus?.(o);for(let i of this.connectionStatusListeners)i(o)}createSocket(e){if(this.options.createSocket)return this.options.createSocket(e);if(typeof WebSocket>"u")throw new Error("Site edit preview bridge requires WebSocket");return new WebSocket(e)}},H=0,R=1,Y=15e3,Z={"get-source-tree":1e4,"get-source-file":1e4,"resolve-source-location":1e4,execute:6e4,"get-operation-result":6e4,undo:2e4,redo:2e4};function I(t,e){return t instanceof Error?t:new Error(e)}function X(t,e){return e.intentional?"WebSocket disconnected":t?.code===1008?t.reason?`Bridge session authentication failed: ${t.reason}`:"Bridge session authentication failed":t?.reason?`WebSocket closed: ${t.reason}`:typeof t?.code=="number"&&t.code!==1005?`WebSocket closed with code ${t.code}`:"WebSocket closed"}function N(t,e){if(!t||typeof t!="object")return null;let o=t[e];return typeof o=="string"||typeof o=="number"?o:null}function ee(t){if(!t||typeof t!="object")return null;let e=t,n=e.data?.resultVersion??e.data?.version??null;return typeof n=="number"?n:null}function pe(t){let e="composition"in t?m(t.composition):m({routeId:t.routeId});return new T({composition:e,initialDocument:t.initialDocument,client:t.client})}var T=class{constructor(e){this.params=e,this.serverConfirmedComposition=null,this.refreshInFlight=null,this.objectGeneration=0,this.styleGeneration=0,this.editContextCache=new Map,this.editContextInFlight=new Map,this.classNameSourceCache=new Map,this.classNameSourceInFlight=new Map,this.styleContextCache=new Map,this.styleContextInFlight=new Map,this.snapshotIdentityStale=!1,this.composition=m(e.composition);let n=e.initialDocument.composition.effectiveTemplateId;if(n!==void 0&&(this.composition.templateId===void 0||this.composition.templateId!==n))throw new Error(`Site edit bridge requires a matching templateId for initial document composition ${JSON.stringify(e.initialDocument.composition)}`);this.currentDocument=e.initialDocument,this.observedDocumentVersion=e.initialDocument.version,this.sessionInitialized=!K(e.initialDocument),this.activeCompositionContext=this.sessionInitialized?{...e.initialDocument.composition}:null}async getDocument(e){this.requireBoundComposition(e);let n=K(this.currentDocument)||this.snapshotIdentityStale;return(n||this.currentDocument.version<this.observedDocumentVersion)&&(this.currentDocument=await this.refreshSnapshot(n?void 0:this.observedDocumentVersion,"get-document"),this.snapshotIdentityStale=!1,this.sessionInitialized=!0),{ok:!0,data:this.currentDocument}}async initializeSession(e){let n=this.requireBoundComposition(e.composition);if(!this.params.client.initializeSession)throw new Error("Site edit bridge client does not support initialize-session");let o=await this.params.client.initializeSession({...e,composition:n});return this.currentDocument=o.data.document,this.observedDocumentVersion=o.data.document.version,this.activeCompositionContext={...o.composition},this.rememberServerConfirmedComposition(o.composition),this.sessionInitialized=!0,this.clearObjectCaches(),o}async getHistoryStatus(e){return this.params.client.getHistoryStatus(this.requireBoundComposition(e))}async getStyleContext(e){let n=this.requireBoundComposition(e),o=C(n),i=this.styleContextCache.get(o);if(i?.generation===this.styleGeneration)return{ok:!0,data:i.value};let r=this.styleContextInFlight.get(o);if(r?.generation===this.styleGeneration)return r.request;let c=this.styleGeneration,s=this.params.client.getStyleContext(n).then(a=>(this.styleGeneration===c&&this.styleContextCache.set(o,{generation:c,value:a.data}),a)).finally(()=>{this.styleContextInFlight.get(o)?.request===s&&this.styleContextInFlight.delete(o)});return this.styleContextInFlight.set(o,{generation:c,request:s}),s}async ensureDocumentVersion(e,n){this.requireBoundComposition(e);let o=await this.refreshSnapshot(n,"ensure-version");if(o.version<n)throw new Error(`Document refresh returned version ${o.version}, expected at least ${n}`);return{ok:!0,data:o}}async acknowledgeDocumentVersion(e,n){if(this.requireBoundComposition(e),n>this.currentDocument.version){if(this.currentDocument.pageComposition.status==="supported"){let o=await this.refreshSnapshot(n,"ensure-version");if(o.version<n)throw new Error(`Document refresh returned version ${o.version}, expected at least ${n}`);return{ok:!0,data:o}}this.currentDocument={...this.currentDocument,version:n},this.clearObjectCaches({preserveStyleContext:!0})}return this.observedDocumentVersion=Math.max(this.observedDocumentVersion,n),{ok:!0,data:this.currentDocument}}async getObjectEditContext(e,n,o){let i=this.requireBoundComposition(n),r=this.objectCacheKey(e,i,o),c=this.editContextCache.get(r);if(c)return{ok:!0,data:c};let s=this.editContextInFlight.get(r);if(s)return s;let a=this.objectGeneration,u=this.params.client.getObjectEditContext(e,i,...o?[o]:[]).then(d=>(this.objectGeneration===a&&this.editContextCache.set(r,d.data),d)).finally(()=>{this.editContextInFlight.get(r)===u&&this.editContextInFlight.delete(r)});return this.editContextInFlight.set(r,u),u}async getClassNameSource(e,n){let o=this.requireBoundComposition(n),i=this.objectCacheKey(e,o),r=this.classNameSourceCache.get(i);if(r)return r;let c=this.classNameSourceInFlight.get(i);if(c)return c;let s=this.objectGeneration,a=this.params.client.getClassNameSource(e,o).then(u=>(this.objectGeneration===s&&this.classNameSourceCache.set(i,u),u)).finally(()=>{this.classNameSourceInFlight.get(i)===a&&this.classNameSourceInFlight.delete(i)});return this.classNameSourceInFlight.set(i,a),a}async getSourceTree(e){return this.params.client.getSourceTree(this.requireBoundComposition(e))}async getSourceFile(e){return this.params.client.getSourceFile({path:e.path,composition:this.requireBoundComposition(e.composition)})}async resolveSourceLocation(e){return this.params.client.resolveSourceLocation({key:e.key,composition:this.requireBoundComposition(e.composition)})}async execute(e,n){let o=S(e);o&&this.composition.templateId!==void 0&&this.requireBoundComposition(o);let i={...e,composition:o??this.composition};return this.params.client.execute(i)}async getOperationResult(e){return this.requireBoundComposition(e.composition),this.params.client.getOperationResult?this.params.client.getOperationResult(e):null}async undo(e,n){return this.params.client.undo(this.requireBoundComposition(e))}async redo(e,n){return this.params.client.redo(this.requireBoundComposition(e))}subscribe(e){return this.params.client.subscribe(n=>{if(n.type==="site-edit.snapshot.changed"&&this.sessionInitialized&&this.isActiveComposition(n.composition)){this.snapshotIdentityStale=!0,this.clearObjectCaches(),e(n);return}if(n.type==="site-edit.document.changed"&&this.sessionInitialized&&this.isActiveComposition(n.composition)){this.observedDocumentVersion=Math.max(this.observedDocumentVersion,n.version),n.version>this.currentDocument.version&&this.clearObjectCaches(),e(n);return}e(n)})}async refreshSnapshot(e,n="ensure-version"){if(typeof e=="number"&&this.currentDocument.version>=e)return g("bridge.document-refresh",{composition:this.composition,routeId:this.composition.routeId,minVersion:e,currentVersion:this.currentDocument.version,deduped:!0,skipped:!0,source:n}),this.currentDocument;let o=C(this.composition),i=this.refreshInFlight;if(i?.compositionKey===o){g("bridge.document-refresh",{composition:this.composition,routeId:this.composition.routeId,minVersion:e,currentVersion:this.currentDocument.version,deduped:!0,source:n});let c=await i.request;if(typeof e!="number"||c.version>=e||this.currentDocument.version>=e)return this.currentDocument}g("bridge.document-refresh",{composition:this.composition,routeId:this.composition.routeId,minVersion:e,currentVersion:this.currentDocument.version,deduped:!1,source:n});let r=this.params.client.getDocument(this.composition).then(c=>(this.currentDocument=c.data,this.activeCompositionContext={...c.data.composition},this.rememberServerConfirmedComposition(c.data.composition),this.observedDocumentVersion=Math.max(this.observedDocumentVersion,c.data.version),this.clearObjectCaches(),this.currentDocument));this.refreshInFlight={compositionKey:o,request:r};try{return await r}finally{this.refreshInFlight?.request===r&&(this.refreshInFlight=null)}}clearObjectCaches(e){this.objectGeneration+=1,this.editContextCache.clear(),this.editContextInFlight.clear(),this.classNameSourceCache.clear(),this.classNameSourceInFlight.clear(),!e?.preserveStyleContext&&(this.styleGeneration+=1,this.styleContextCache.clear(),this.styleContextInFlight.clear())}objectCacheKey(e,n,o){return`${C(n)}\0${e}\0${ne(o)}`}rememberServerConfirmedComposition(e){!e||typeof e.routeId!="string"||(this.serverConfirmedComposition={...e})}isAcceptedComposition(e){if(C(e)===C(this.composition))return!0;let n=this.serverConfirmedComposition;return n!==null&&x(n)===x(B(e))}requireBoundComposition(e){let n=e===void 0?this.composition:m(e);if(!this.isAcceptedComposition(n))throw new Error(`Site edit bridge is bound to composition ${JSON.stringify(this.composition)}, received ${JSON.stringify(n)}`);return m(n)}isActiveComposition(e){let n=this.activeCompositionContext??B(this.composition);return x(e)===x(n)}};function K(t){return t.version===0&&t.entries.length===0}function te(t){let e=t;return{...e,data:{...e.data,document:j(e.data.document,e.composition)}}}function j(t,e){let n=t,o=_(n.routeId?n:{...n,routeId:e?.routeId??n.composition?.routeId});return e?{...o,composition:e}:o}function m(t){if(t&&typeof t=="object"&&typeof t.routeId=="string"){let e="effectiveTemplateId"in t?t.effectiveTemplateId:"templateId"in t?t.templateId:void 0;return{routeId:t.routeId,...typeof e=="string"?{templateId:e}:{}}}throw new Error("SITE_EDIT_COMPOSITION_SESSION_REQUIRED: a composition selector is required")}function C(t){return JSON.stringify([t.routeId,t.templateId??null])}function ne(t){return t?JSON.stringify([t.key,t.instanceIndex??null,t.instanceCount??null]):""}function x(t){return JSON.stringify([t.routeId,t.effectiveTemplateId??null])}function B(t){return{routeId:t.routeId,...t.templateId?{effectiveTemplateId:t.templateId}:{}}}function S(t){if(t&&typeof t=="object"){let e=t;if(e.composition&&typeof e.composition=="object"){let n=e.composition;if(typeof n.routeId=="string")return{routeId:n.routeId,...typeof n.templateId=="string"?{templateId:n.templateId}:{}}}}}function oe(t,e,n){let o=m(e==="execute"?S(n.request):n.composition),i={id:t,kind:e,composition:o};switch(e){case"initialize-session":case"get-document":case"get-history-status":case"get-style-context":case"get-source-tree":case"undo":case"redo":return{type:"request",payload:{...i,...n.mutationContext?{mutationContext:n.mutationContext}:{}}};case"get-object-edit-context":return{type:"request",payload:{...i,key:String(n.key),...n.selectionRef?{selectionRef:n.selectionRef}:{}}};case"get-class-name-source":case"resolve-source-location":return{type:"request",payload:{...i,key:String(n.key)}};case"get-source-file":return{type:"request",payload:{...i,path:String(n.path)}};case"execute":case"get-operation-result":return{type:"request",payload:{...i,request:{...n.request,composition:S(n.request)??o}}}}}export{v as SiteEditWebSocketClient,pe as createSiteEditBridge};
@@ -13,6 +13,7 @@ export const SITE_EDIT_ENGINE_WORKER_METHODS = [
13
13
  "getSourceFile",
14
14
  "resolveSourceLocation",
15
15
  "execute",
16
+ "getOperationResult",
16
17
  "undo",
17
18
  "redo",
18
19
  ];
@@ -1,4 +1,4 @@
1
- import{parentPort as Xe,workerData as et}from"node:worker_threads";function M(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 se from"node:http";import _ from"node:fs";import{createHash as oe,randomBytes as Ce,timingSafeEqual as Ee}from"node:crypto";import m from"node:path";import{WebSocket as re,WebSocketServer as xe}from"ws";import{createPreviewSiteEditEngineRuntime as Re,openFileHistoryStore as be,resolveManagedPageTemplateComposition as ve,scanSiteEditCompositionsFromFiles as ke}from"@vcp-dev/site-edit-engine";import{resolveNextAppRouteId as _e,scanNextAppRouterRoutesFromFiles as Te}from"@vcp-dev/site-edit-engine/next-app-router";import{SiteEditSourceWatcher as Oe}from"@vcp-dev/site-edit-engine/source-watcher";function G(t){let e=new Map,n=[],i=new Map,o=[],s=t.pageComposition.status==="supported"?t.pageComposition.placementUnitKeys:[],r=new Map(s.map((a,d)=>[a,d])),c=t.pageComposition.status==="supported"?{status:"supported",containerKey:t.pageComposition.containerKey,hasBusinessMembers:t.pageComposition.hasBusinessMembers,placementUnitKeys:t.pageComposition.placementUnitKeys,placements:t.pageComposition.placements.map(a=>({placementKey:a.placementKey,placementUnitKey:a.placementUnitKey,relation:a.relation}))}:{status:"unsupported",reason:t.pageComposition.reason,diagnostics:t.pageComposition.diagnostics},p=t.entries.flatMap((a,d)=>a.dynamicDataSummary?[[d,a.dynamicDataSummary]]:[]),u=new Map(t.entries.map((a,d)=>[a.key,d])),l=[];for(let[a,d]of t.entries.entries()){let f=d.pageCompositionActionScope;if(!f)continue;if(f.kind!=="source-siblings"){l.push([a,{kind:f.kind}]);continue}let O=f.siblingKeys.map(b=>{let v=u.get(b);if(v===void 0)throw new Error("Render entry "+d.key+" references missing source sibling "+b);return v});l.push([a,{kind:"source-siblings",siblingEntryIndexes:O}])}let S=a=>{let d=e.get(a);if(typeof d=="number")return d;let f=n.length;return n.push(a),e.set(a,f),f},J=a=>{let d=null;for(let f of pe(a)){let O=`${d??"root"}\0${f}`,b=i.get(O);if(typeof b=="number"){d=b;continue}let v=o.length;o.push([d,S(f)]),i.set(O,v),d=v}if(d===null)throw new Error("Document key must not be empty");return d};return{encoding:"segment-trie-v1",siteId:t.siteId,snapshotId:t.snapshotId,composition:{...t.composition},routeId:t.composition.routeId,version:t.version,pageComposition:c,tokens:n,nodes:o,entries:t.entries.map(a=>{let d=a.pageCompositionUnitKey?r.get(a.pageCompositionUnitKey)??-1:-1;if(a.pageCompositionUnitKey&&d<0)throw new Error(`Render entry ${a.key} references unknown page composition unit ${a.pageCompositionUnitKey}`);return[J(a.key),he(a.operationSummary),...d>=0?[d]:[]]}),...l.length>0?{pageCompositionActionScopes:l}:{},...t.entries.every(a=>a.parentKey!==void 0)?{entryParentNodeIds:t.entries.map(a=>a.parentKey===null?null:J(a.parentKey))}:{},...p.length>0?{dynamicDataSummaries:p}:{}}}function 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=Q(t,n);if(i<0)return e.push(t),e;for(e.push(t.slice(0,i)),n=i;n<t.length;){if(i=Q(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 Q(t,e){let n=t.indexOf("/",e),i=t.indexOf("::",e);return n<0?i:i<0?n:Math.min(n,i)}var Y="SITE_EDIT_COMPOSITION_SESSION_MISMATCH",V="SITE_EDIT_COMPOSITION_SESSION_REQUIRED";var g=class t{constructor(){}static parseMessage(e,n={}){let i=JSON.parse(e);if(!t.isMessage(i,n))throw new Error("Invalid site edit bridge message");return i}static stringifyMessage(e){return JSON.stringify(e)}static extractRequestInfo(e){if(h(e)&&h(e.payload)){let n=typeof e.payload.id=="string"?e.payload.id:"unknown",i=this.isRequestKind(e.payload.kind)?e.payload.kind:"get-document";return{id:n,kind:i}}return{id:"unknown",kind:"get-document"}}static isRequestKind(e){return e==="initialize-session"||e==="get-document"||e==="get-history-status"||e==="get-style-context"||e==="get-object-edit-context"||e==="get-class-name-source"||e==="get-source-tree"||e==="get-source-file"||e==="resolve-source-location"||e==="execute"||e==="undo"||e==="redo"}static isMessage(e,n={}){return!h(e)||typeof e.type!="string"?!1:e.type==="request"?le(e.payload,n):e.type==="response"||e.type==="error"?h(e.payload)&&typeof e.payload.id=="string":e.type==="event"?h(e.payload)&&h(e.payload.event):e.type==="auth"?h(e.payload)&&typeof e.payload.key=="string":e.type==="auth-ok"&&h(e.payload)&&e.payload.ok===!0}},A=class{constructor(e){this.options=e,this.session={subscribedCompositionKeys:new Set},this.messageQueue=new P,this.eventDispatcher=new B(n=>{this.sendJson(n)}),this.unsubscribe=e.engine.subscribe(n=>{this.handleEngineEvent(n)}),e.socket.onmessage=n=>{try{this.messageQueue.enqueue(()=>this.handleRawMessage(n.data))}catch(i){this.sendJson({type:"error",payload:{id:"unknown",kind:"get-document",message:i instanceof Error?i.message:"Bridge queue overflow"}}),e.socket.close(1013,"bridge busy")}},e.socket.onclose=()=>{this.unsubscribe(),this.session.activeComposition=void 0,this.session.subscribedCompositionKeys.clear()}}async handleMessage(e){try{let n=e;if(n.type!=="request")return;let i=n.payload,{id:o}=i;switch(i.kind){case"initialize-session":{let s=D(i),r=await this.resolve(s),c=await this.options.engine.initializeSession({composition:r.context,...i.mutationContext?{mutationContext:i.mutationContext}:{}});this.activateSession(r.context),this.sendJson({type:"response",payload:{id:o,kind:i.kind,result:I({...c,data:{...c.data,document:X(c.data.document)}},r.context)}});return}case"get-document":{let s=await this.resolveWireContext(i),r=await this.options.engine.getDocument(s);this.sendResult(o,i.kind,Se(r,s));return}case"get-history-status":{let s=await this.resolveWireContext(i),r=await this.options.engine.getHistoryStatus(s);this.sendResult(o,i.kind,I(r,s));return}case"get-style-context":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getStyleContext(s),s));return}case"get-object-edit-context":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getObjectEditContext(i.key,s,i.selectionRef),s));return}case"get-class-name-source":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getClassNameSource(i.key,s),s));return}case"get-source-tree":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getSourceTree(s),s));return}case"get-source-file":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getSourceFile({path:i.path,composition:s}),s));return}case"resolve-source-location":{let s=await this.resolveWireContext(i),r=I(await this.options.engine.resolveSourceLocation({key:i.key,composition:s}),s);this.sendResult(o,i.kind,r);return}case"execute":{let s=await this.resolveOperationWireContext(i.request),r=await this.resolveWireContext(i);if(w(s)!==w(r))throw new C(Y,"The execute request composition does not match its operation composition.");let c=await this.normalizeOperationRequest(i.request,s);await this.handleBufferedOperation(o,i.kind,()=>this.options.engine.execute(c));return}case"undo":case"redo":{let s=await this.resolveWireContext(i);await this.handleBufferedOperation(o,i.kind,()=>i.kind==="undo"?this.options.engine.undo(s):this.options.engine.redo(s));return}}}catch(n){let i=g.extractRequestInfo(e);this.sendJson({type:"error",payload:{...i,message:F(n),code:N(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(V,"Initialize a composition session before issuing this request.");if(w(i)!==w(n.context))throw new C(Y,"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=ye(e);return this.resolveAndAssert(n)}activateSession(e){this.session.activeComposition=e,this.session.subscribedCompositionKeys.clear(),this.session.subscribedCompositionKeys.add(w(e))}async normalizeOperationRequest(e,n){let i={...e,composition:Z(n)};if(i.target.kind==="route"){let o=i.target,s=D(o),r=await this.resolveAndAssert(s);i.target={...o,composition:Z(r)}}return i}handleEngineEvent(e){let n=e?.composition;if(!me(n))return;let i=w(n);this.session.subscribedCompositionKeys.has(i)&&(this.eventDispatcher.push(e),e.type==="site-edit.graph.invalidated"&&i===Ie(this.session)&&(this.session.activeComposition=void 0,this.session.subscribedCompositionKeys.delete(i)))}sendResult(e,n,i){this.sendJson({type:"response",payload:{id:e,kind:n,result:i}})}async handleRawMessage(e){try{await this.handleMessage(g.parseMessage(e,{validateOperationRequest:this.options.validateOperationRequest}))}catch(n){let i=we(e);this.sendJson({type:"error",payload:{...i,message:F(n),code:N(n)}})}}sendJson(e){this.options.socket.send(g.stringifyMessage(e))}async handleBufferedOperation(e,n,i){this.eventDispatcher.beginBuffering();try{let o=await i();this.sendResult(e,n,o)}catch(o){this.sendJson({type:"error",payload:{id:e,kind:n,message:F(o),code:N(o)}})}finally{this.eventDispatcher.flush()}}},C=class extends Error{constructor(e,n){super(n),this.code=e,this.name="BridgeProtocolError"}},B=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))}},P=class{constructor(e=64){this.maxQueued=e,this.queue=Promise.resolve(),this.queued=0}enqueue(e){if(this.queued>=this.maxQueued)throw new Error("Bridge request queue is full");this.queued+=1;let n=async()=>{this.queued-=1,await e()},i=this.queue.then(n,n);return this.queue=i.then(()=>{},()=>{}),i}};function le(t,e){if(!h(t)||typeof t.id!="string"||!g.isRequestKind(t.kind))return!1;let n=k(t.composition);switch(t.kind){case"initialize-session":return n&&(t.mutationContext===void 0||K(t.mutationContext));case"get-document":case"get-style-context":return n;case"get-object-edit-context":return typeof t.key=="string"&&n&&fe(t.selectionRef);case"get-class-name-source":case"resolve-source-location":return typeof t.key=="string"&&n;case"get-history-status":return n;case"get-source-tree":return n;case"get-source-file":return typeof t.path=="string"&&n;case"execute":return n&&ge(t.request)&&(t.request.mutationContext===void 0||K(t.request.mutationContext))&&(e.validateOperationRequest?.(t.request)??!0);case"undo":case"redo":return n&&t.mutationContext===void 0||n&&K(t.mutationContext)}}function fe(t){if(t===void 0)return!0;if(!h(t)||typeof t.key!="string"||t.key.length===0)return!1;let e=t.instanceIndex,n=t.instanceCount;return e!==void 0&&(typeof e!="number"||!Number.isInteger(e)||e<0)||n!==void 0&&(typeof n!="number"||!Number.isInteger(n)||n<=0)||typeof e=="number"&&typeof n=="number"&&e>=n?!1:Object.keys(t).every(i=>i==="key"||i==="instanceIndex"||i==="instanceCount")}function ge(t){return h(t)&&typeof t.id=="string"&&typeof t.siteId=="string"&&typeof t.baseSnapshotId=="string"&&k(t.composition)&&typeof t.kind=="string"&&h(t.target)&&(t.target.kind!=="route"||k(t.target.composition))&&typeof t.documentVersion=="number"&&Number.isInteger(t.documentVersion)&&t.documentVersion>=0&&h(t.params)}function k(t){return h(t)&&typeof t.routeId=="string"&&t.routeId.length>0&&(t.templateId===void 0||typeof t.templateId=="string"&&t.templateId.length>0)&&Object.keys(t).every(e=>e==="routeId"||e==="templateId")}function me(t){return h(t)&&typeof t.routeId=="string"&&(t.effectiveTemplateId===void 0||typeof t.effectiveTemplateId=="string")}function D(t){if(k(t.composition))return t.composition;throw new C(V,"A composition selector is required for this request.")}function ye(t){if(h(t)&&k(t.composition))return t.composition;throw new C(V,"A composition selector is required for execute.")}function Z(t){return{routeId:t.routeId,...t.effectiveTemplateId?{templateId:t.effectiveTemplateId}:{}}}function Ie(t){return t.activeComposition?w(t.activeComposition):null}function w(t){return JSON.stringify([t.routeId,t.effectiveTemplateId??null])}function I(t,e){return h(t)&&t.ok===!0?{...t,composition:e}:t}function Se(t,e){return!h(t)||t.ok!==!0?t:{...t,...e?{composition:e}:{},data:X(t.data)}}function X(t){let e=t;return G(e.routeId?e:{...e,routeId:e.composition.routeId})}function h(t){return typeof t=="object"&&t!==null}function K(t){return h(t)&&typeof t.editingSessionId=="string"&&t.editingSessionId.length>0&&typeof t.lockId=="string"&&t.lockId.length>0&&typeof t.ownerId=="string"&&t.ownerId.length>0&&typeof t.leaseAssertion=="string"&&t.leaseAssertion.length>0}function N(t){if(!(!h(t)||typeof t.code!="string"||t.code.length===0))return t.code}function F(t){return t instanceof Error||h(t)&&typeof t.message=="string"&&t.message.length>0?t.message:"Unknown websocket operation failure"}function we(t){try{return g.extractRequestInfo(JSON.parse(t))}catch{return{id:"unknown",kind:"get-document"}}}var H=class{constructor(){this.tail=Promise.resolve()}run(e){let n=this.tail.then(e,e);return this.tail=n.then(()=>{},()=>{}),n}};import{SiteEditOperationRequestSchema as Ae,computeSiteEditCompositionKey as E}from"@vcp-dev/contracts";var He="127.0.0.1",Me=30218,De="/__vcp/site-edit/bridge",ae=6*1024*1024,Ke=ae*2,Ne=3e3,ee=50,W=".vcp/current-snapshot.json",te="__VCP_SITE_EDIT_BRIDGE_SERVERS__";var $=class{constructor(e,n=se.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 H,this.eventListeners=new Set,this.routes=[],this.compositions=[],this.compositionFiles=[],this.compositionResolutionError=null,this.launchCandidateEntries=null,this.stopWatching=null,this.stopWebSocketServer=null,this.pendingChangedFiles=new Set,this.fileChangeTimer=null,this.isStarted=!1,this.stopping=!1,this.runtimeVersionFloors=new Map,this.activeHistoryStore=null,this.versionPersistence=Promise.resolve(),this.bridgeEngine=null,this.lastNotifiedHealth=null}start(e={}){if(!this.isStarted){this.stopping=!1;try{_.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=$e({server:this.server,path:this.options.path,sessionKey:this.options.sessionKey,host:this.options.host,allowedOrigins:this.options.allowedOrigins,engine:this.bridgeEngine});this.stopWebSocketServer=n.stop}this.stopWatching=new Oe({projectRoot:this.options.projectRoot,watch_dirs:Be(this.options.runtime.watch_dirs),interval_ms:this.options.runtime.watch_interval_ms,debounce_ms:this.options.runtime.watch_debounce_ms??ee,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=Ue(),n=We(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??Re)({...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=Ve(e.composition),o=this.getRuntime(),s=y(i);await o.initializeComposition(s);let c=o.getDocument(s).data;await this.recordRuntimeVersion(c.version,i);let p=(await o.getHistoryStatus()).data;return{ok:!0,composition:i,data:{document:c,historyStatus:p}}}),getDocument:async e=>{let n=this.getRuntime(),i=y(e);await n.initializeComposition(i);let o=n.getDocument(i);return await this.recordRuntimeVersion(o.data.version,e),{...o,composition:e}},getHistoryStatus:async e=>({...await this.getRuntime().getHistoryStatus(),composition:e}),getStyleContext:async e=>this.getRuntime().getStyleContext(y(e)),getObjectEditContext:async(e,n,i)=>this.getRuntime().getObjectEditContext(e,y(n),i),getClassNameSource:async(e,n)=>this.getRuntime().getClassNameSource(e,y(n)),getSourceTree:async e=>this.getRuntime().getSourceTree(y(e)),getSourceFile:async e=>this.getRuntime().getSourceFile({path:e.path,composition:y(e.composition)}),resolveSourceLocation:async e=>this.getRuntime().resolveSourceLocation({key:e.key,composition:y(e.composition)}),execute:(e,n)=>this.mutationQueue.run(async()=>{let i=await this.bindHistorySession(this.options.snapshotId);if(!i.ok)return q(i,e);let o=await this.getRuntime().executeOperation(e);return o.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(o.data.resultVersion,o.composition),o}),undo:e=>this.mutationQueue.run(async()=>{let n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)return q(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 q(n,void 0,e);let i=await this.getRuntime().redo();return i.data?.resultVersion!==void 0&&await this.recordRuntimeVersion(i.data.resultVersion,i.composition??e),i.composition?i:{...i,composition:e}}),subscribe:e=>(this.eventListeners.add(e),()=>this.eventListeners.delete(e))}}async bindHistorySession(e){if(!this.options.historyRoot)return{ok:!1,code:"RECOVERY_PERSIST_FAILED",message:"Durable edit history is not configured."};if(this.activeHistorySessionId===e)return{ok:!0};let n=this.historySessionTransition.then(async()=>{if(this.activeHistorySessionId===e)return;let i=await(this.dependencies.openHistoryStore??be)(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.compositions[0]?.context;if(s){let r=E(s);this.runtimeVersionFloors.set(r,Math.max(this.runtimeVersionFloors.get(r)??0,o))}this.createRuntime(i,e)});this.historySessionTransition=n.catch(()=>{});try{return await n,{ok:!0}}catch{return{ok:!1,code:"RECOVERY_PERSIST_FAILED",message:"Durable edit history could not be opened."}}}recordRuntimeVersion(e,n){let i=n?E(n):null;i&&this.runtimeVersionFloors.set(i,Math.max(this.runtimeVersionFloors.get(i)??0,e));let o=this.activeHistoryStore;if(!o?.writeDocumentVersion)return Promise.resolve();let s=i?this.runtimeVersionFloors.get(i)??e:e;return this.versionPersistence=this.versionPersistence.then(()=>o.writeDocumentVersion(s)).catch(()=>{}),this.versionPersistence}handleFileChanged(e){this.handleFilesChanged([e])}handleFilesChanged(e){for(let i of e)this.pendingChangedFiles.add(i);this.fileChangeTimer&&clearTimeout(this.fileChangeTimer);let n=this.options.runtime.watch_debounce_ms??ee;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(Ze)&&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,W),"utf8"),n=JSON.parse(e),i=typeof n.snapshot_id=="string"?n.snapshot_id:"";return!i||j(i)!==i?(console.warn("[vcp-site-edit] current-snapshot marker has no valid snapshot_id"),null):i}catch(e){return console.warn(`[vcp-site-edit] current-snapshot marker unreadable: ${e instanceof Error?e.message:String(e)}`),null}}async advanceSnapshotId(e){if(this.stopping||!this.isStarted||e===this.options.snapshotId)return;let n=this.options.snapshotId;this.options.snapshotId=e;try{if(this.options.historyRoot){let o=await this.bindHistorySession(e);if(!o.ok)throw new Error(`${o.code}: ${o.message}`)}else this.createRuntime()}catch(o){this.options.snapshotId=n,console.warn(`[vcp-site-edit] snapshot identity advance rolled back to ${n}: ${o instanceof Error?o.message:String(o)}`);return}let i=new Date().toISOString();for(let o of this.compositions){let s={type:"site-edit.snapshot.changed",siteId:this.options.siteId,composition:o.context,snapshotId:e,previousSnapshotId:n,at:i};for(let r of this.eventListeners)try{r(s)}catch(c){console.warn(`[vcp-site-edit] snapshot.changed listener failed: ${c instanceof Error?c.message:String(c)}`)}}try{this.options.onSnapshotIdChanged?.(e,n)}catch(o){console.warn(`[vcp-site-edit] onSnapshotIdChanged callback failed: ${o instanceof Error?o.message:String(o)}`)}}refreshCompositions(e=!1){try{let n=Pe(this.options.projectRoot),i=Te(n),o=i.length>0?i:(this.options.runtime.routes??[]).map(u=>({...u})),s=ke({files:n});if(s.length===0)throw new Error("No canonical App Router composition is indexed by the preview bridge.");let r=JSON.stringify(s.filter(u=>u.context.effectiveTemplateId!==void 0).map(u=>u.entryFile).sort());if(e&&(this.launchCandidateEntries=r),this.launchCandidateEntries!==r)throw new Error("SITE_EDIT_RUNTIME_RELOAD_REQUIRED: Candidate route collection changed since preview launch");let c=new Map(this.compositions.map(u=>[E(u.context),u])),p=new Map(s.map(u=>[E(u.context),u]));if(this.runtime){for(let[u,l]of c){let S=p.get(u);(!S||S.entryFile!==l.entryFile)&&this.runtime.unregisterComposition(y(l.context))}for(let[u,l]of p){let S=c.get(u);(!S||S.entryFile!==l.entryFile)&&this.runtime.registerComposition(l.context,l.entryFile)}}return this.routes=o,this.compositions=s,this.compositionFiles=n,this.compositionResolutionError=null,this.notifyHealthChanged(),!0}catch(n){let i=n instanceof Error?n:new Error(String(n));if(this.compositionResolutionError=i,e)throw i;return this.notifyHealthChanged(),!1}}resolveComposition(e){if(this.compositionResolutionError)throw this.compositionResolutionError;let n=_e(e.routeId,this.routes,this.options.basePath);if(!n)throw new Error(`Route is not indexed by the preview bridge: ${e.routeId}`);let i=this.routes.find(r=>r.routeId===n);if(!i)throw new Error(`Route is not indexed by the preview bridge: ${e.routeId}`);let o=ve({selector:{routeId:n,...e.templateId!==void 0?{templateId:e.templateId}:{}},files:this.compositionFiles,canonicalEntryFile:i.entryFile}),s=E(o.context);if(!this.compositions.some(r=>E(r.context)===s))throw new Error(`Composition is not registered by the preview bridge: ${s}`);return o}getInitialDocumentVersions(){return this.compositions.flatMap(e=>{let n=this.runtimeVersionFloors.get(E(e.context));return n===void 0?[]:[{composition:e.context,version:n}]})}getRuntime(){if(!this.runtime)throw new Error("VCP site edit preview bridge runtime is not ready");return this.runtime}};function ce(t){let e=new $(Fe(t),se.createServer(),!1);return e.start({listen:!1,webSocket:!1}),{engine:e.getEngine(),getHealth:()=>e.getHealth(),stop:()=>e.stop()}}function Fe(t){return{tenantId:t.tenantId,siteId:t.siteId,snapshotId:t.snapshotId,projectRoot:m.resolve(t.projectRoot??process.cwd()),basePath:t.basePath??"",host:t.host??He,port:t.port??Me,path:t.path??De,sessionKey:t.sessionKey??Ye(),historyRoot:t.historyRoot,allowedOrigins:t.allowedOrigins??[],runtime:t.runtime??{},onSnapshotIdChanged:t.onSnapshotIdChanged,onHealthChanged:t.onHealthChanged}}function Be(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 Pe(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 c of r){if(c.name.startsWith(".")&&c.name!==".vcp")continue;if(c.isDirectory()){if(i.has(c.name))continue;o(m.join(s,c.name));continue}if(!c.isFile())continue;let p=m.join(s,c.name),u="";try{u=_.readFileSync(p,"utf8")}catch{}e.push({path:m.relative(t,p).replaceAll(m.sep,"/"),content:u})}};for(let s of n)o(m.join(t,s));return e.sort((s,r)=>s.path.localeCompare(r.path))}function Ve(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),j(t.siteId),j(t.snapshotId),oe("sha256").update(t.editingSessionId).digest("hex").slice(0,32))}function j(t){return/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(t)&&t!=="."&&t!==".."?t:oe("sha256").update(t).digest("hex").slice(0,32)}function Ue(){let t=globalThis;return t[te]??=new Map,t[te]}function We(t){return`${t.projectRoot}:${t.host}:${t.port}:${t.path}:${t.historyRoot??""}`}function q(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 $e(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=>Ae.safeParse(r).success})},o=(s,r,c)=>{if(!je(s,t))return;let p=ze(s,t);if(!p){r.write(`HTTP/1.1 401 Unauthorized\r
1
+ import{parentPort as Xe,workerData as et}from"node:worker_threads";function M(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 Ce,timingSafeEqual as Ee}from"node:crypto";import m from"node:path";import{WebSocket as re,WebSocketServer as Re}from"ws";import{createPreviewSiteEditEngineRuntime as xe,openFileHistoryStore as be,resolveManagedPageTemplateComposition as ve,scanSiteEditCompositionsFromFiles as ke}from"@vcp-dev/site-edit-engine";import{resolveNextAppRouteId as _e,scanNextAppRouterRoutesFromFiles as Te}from"@vcp-dev/site-edit-engine/next-app-router";import{SiteEditSourceWatcher as Oe}from"@vcp-dev/site-edit-engine/source-watcher";function 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,d)=>[c,d])),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},p=t.entries.flatMap((c,d)=>c.dynamicDataSummary?[[d,c.dynamicDataSummary]]:[]),u=new Map(t.entries.map((c,d)=>[c.key,d])),l=[];for(let[c,d]of t.entries.entries()){let f=d.pageCompositionActionScope;if(!f)continue;if(f.kind!=="source-siblings"){l.push([c,{kind:f.kind}]);continue}let O=f.siblingKeys.map(b=>{let v=u.get(b);if(v===void 0)throw new Error("Render entry "+d.key+" references missing source sibling "+b);return v});l.push([c,{kind:"source-siblings",siblingEntryIndexes:O}])}let S=c=>{let d=e.get(c);if(typeof d=="number")return d;let f=n.length;return n.push(c),e.set(c,f),f},Q=c=>{let d=null;for(let f of pe(c)){let O=`${d??"root"}\0${f}`,b=i.get(O);if(typeof b=="number"){d=b;continue}let v=o.length;o.push([d,S(f)]),i.set(O,v),d=v}if(d===null)throw new Error("Document key must not be empty");return d};return{encoding:"segment-trie-v1",siteId:t.siteId,snapshotId:t.snapshotId,composition:{...t.composition},routeId:t.composition.routeId,version:t.version,pageComposition:a,tokens:n,nodes:o,entries:t.entries.map(c=>{let d=c.pageCompositionUnitKey?r.get(c.pageCompositionUnitKey)??-1:-1;if(c.pageCompositionUnitKey&&d<0)throw new Error(`Render entry ${c.key} references unknown page composition unit ${c.pageCompositionUnitKey}`);return[Q(c.key),he(c.operationSummary),...d>=0?[d]:[]]}),...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))}:{},...p.length>0?{dynamicDataSummaries:p}:{}}}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",V="SITE_EDIT_COMPOSITION_SESSION_REQUIRED";var g=class t{constructor(){}static parseMessage(e,n={}){let i=JSON.parse(e);if(!t.isMessage(i,n))throw new Error("Invalid site edit bridge message");return i}static stringifyMessage(e){return JSON.stringify(e)}static extractRequestInfo(e){if(h(e)&&h(e.payload)){let n=typeof e.payload.id=="string"?e.payload.id:"unknown",i=this.isRequestKind(e.payload.kind)?e.payload.kind:"get-document";return{id:n,kind:i}}return{id:"unknown",kind:"get-document"}}static isRequestKind(e){return e==="initialize-session"||e==="get-document"||e==="get-history-status"||e==="get-style-context"||e==="get-object-edit-context"||e==="get-class-name-source"||e==="get-source-tree"||e==="get-source-file"||e==="resolve-source-location"||e==="execute"||e==="get-operation-result"||e==="undo"||e==="redo"}static isMessage(e,n={}){return!h(e)||typeof e.type!="string"?!1:e.type==="request"?le(e.payload,n):e.type==="response"||e.type==="error"?h(e.payload)&&typeof e.payload.id=="string":e.type==="event"?h(e.payload)&&h(e.payload.event):e.type==="auth"?h(e.payload)&&typeof e.payload.key=="string":e.type==="auth-ok"&&h(e.payload)&&e.payload.ok===!0}},A=class{constructor(e){this.options=e,this.session={subscribedCompositionKeys:new Set},this.messageQueue=new P,this.eventDispatcher=new B(n=>{this.sendJson(n)}),this.unsubscribe=e.engine.subscribe(n=>{this.handleEngineEvent(n)}),e.socket.onmessage=n=>{try{this.messageQueue.enqueue(()=>this.handleRawMessage(n.data))}catch(i){this.sendJson({type:"error",payload:{id:"unknown",kind:"get-document",message:i instanceof Error?i.message:"Bridge queue overflow"}}),e.socket.close(1013,"bridge busy")}},e.socket.onclose=()=>{this.unsubscribe(),this.session.activeComposition=void 0,this.session.subscribedCompositionKeys.clear()}}async handleMessage(e){try{let n=e;if(n.type!=="request")return;let i=n.payload,{id:o}=i;switch(i.kind){case"initialize-session":{let s=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,Se(r,s));return}case"get-history-status":{let s=await this.resolveWireContext(i),r=await this.options.engine.getHistoryStatus(s);this.sendResult(o,i.kind,I(r,s));return}case"get-style-context":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getStyleContext(s),s));return}case"get-object-edit-context":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getObjectEditContext(i.key,s,i.selectionRef),s));return}case"get-class-name-source":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getClassNameSource(i.key,s),s));return}case"get-source-tree":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getSourceTree(s),s));return}case"get-source-file":{let s=await this.resolveWireContext(i);this.sendResult(o,i.kind,I(await this.options.engine.getSourceFile({path:i.path,composition:s}),s));return}case"resolve-source-location":{let s=await this.resolveWireContext(i),r=I(await this.options.engine.resolveSourceLocation({key:i.key,composition:s}),s);this.sendResult(o,i.kind,r);return}case"execute":case"get-operation-result":{let s=await this.resolveOperationWireContext(i.request),r=await this.resolveWireContext(i);if(w(s)!==w(r))throw new C(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=g.extractRequestInfo(e);this.sendJson({type:"error",payload:{...i,message:N(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(V,"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=ye(e);return this.resolveAndAssert(n)}activateSession(e){this.session.activeComposition=e,this.session.subscribedCompositionKeys.clear(),this.session.subscribedCompositionKeys.add(w(e))}async normalizeOperationRequest(e,n){let i={...e,composition: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(!me(n))return;let i=w(n);this.session.subscribedCompositionKeys.has(i)&&(this.eventDispatcher.push(e),e.type==="site-edit.graph.invalidated"&&i===Ie(this.session)&&(this.session.activeComposition=void 0,this.session.subscribedCompositionKeys.delete(i)))}sendResult(e,n,i){this.sendJson({type:"response",payload:{id:e,kind:n,result:i}})}async handleRawMessage(e){try{await this.handleMessage(g.parseMessage(e,{validateOperationRequest:this.options.validateOperationRequest}))}catch(n){let i=we(e);this.sendJson({type:"error",payload:{...i,message:N(n),code:F(n)}})}}sendJson(e){this.options.socket.send(g.stringifyMessage(e))}async handleBufferedOperation(e,n,i){this.eventDispatcher.beginBuffering();try{let o=await i();this.sendResult(e,n,o)}catch(o){this.sendJson({type:"error",payload:{id:e,kind:n,message:N(o),code:F(o)}})}finally{this.eventDispatcher.flush()}}},C=class extends Error{constructor(e,n){super(n),this.code=e,this.name="BridgeProtocolError"}},B=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))}},P=class{constructor(e=64){this.maxQueued=e,this.queue=Promise.resolve(),this.queued=0}enqueue(e){if(this.queued>=this.maxQueued)throw new Error("Bridge request queue is full");this.queued+=1;let n=async()=>{this.queued-=1,await e()},i=this.queue.then(n,n);return this.queue=i.then(()=>{},()=>{}),i}};function le(t,e){if(!h(t)||typeof t.id!="string"||!g.isRequestKind(t.kind))return!1;let n=k(t.composition);switch(t.kind){case"initialize-session":return n&&(t.mutationContext===void 0||K(t.mutationContext));case"get-document":case"get-style-context":return n;case"get-object-edit-context":return typeof t.key=="string"&&n&&fe(t.selectionRef);case"get-class-name-source":case"resolve-source-location":return typeof t.key=="string"&&n;case"get-history-status":return n;case"get-source-tree":return n;case"get-source-file":return typeof t.path=="string"&&n;case"execute":case"get-operation-result":return n&&ge(t.request)&&(t.request.mutationContext===void 0||K(t.request.mutationContext))&&(e.validateOperationRequest?.(t.request)??!0);case"undo":case"redo":return n&&t.mutationContext===void 0||n&&K(t.mutationContext)}}function fe(t){if(t===void 0)return!0;if(!h(t)||typeof t.key!="string"||t.key.length===0)return!1;let e=t.instanceIndex,n=t.instanceCount;return e!==void 0&&(typeof e!="number"||!Number.isInteger(e)||e<0)||n!==void 0&&(typeof n!="number"||!Number.isInteger(n)||n<=0)||typeof e=="number"&&typeof n=="number"&&e>=n?!1:Object.keys(t).every(i=>i==="key"||i==="instanceIndex"||i==="instanceCount")}function ge(t){return h(t)&&typeof t.id=="string"&&typeof t.siteId=="string"&&typeof t.baseSnapshotId=="string"&&k(t.composition)&&typeof t.kind=="string"&&h(t.target)&&(t.target.kind!=="route"||k(t.target.composition))&&typeof t.documentVersion=="number"&&Number.isInteger(t.documentVersion)&&t.documentVersion>=0&&h(t.params)}function k(t){return h(t)&&typeof t.routeId=="string"&&t.routeId.length>0&&(t.templateId===void 0||typeof t.templateId=="string"&&t.templateId.length>0)&&Object.keys(t).every(e=>e==="routeId"||e==="templateId")}function me(t){return h(t)&&typeof t.routeId=="string"&&(t.effectiveTemplateId===void 0||typeof t.effectiveTemplateId=="string")}function D(t){if(k(t.composition))return t.composition;throw new C(V,"A composition selector is required for this request.")}function ye(t){if(h(t)&&k(t.composition))return t.composition;throw new C(V,"A composition selector is required for execute.")}function X(t){return{routeId:t.routeId,...t.effectiveTemplateId?{templateId:t.effectiveTemplateId}:{}}}function Ie(t){return t.activeComposition?w(t.activeComposition):null}function w(t){return JSON.stringify([t.routeId,t.effectiveTemplateId??null])}function I(t,e){return h(t)&&t.ok===!0?{...t,composition:e}:t}function Se(t,e){return!h(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 h(t){return typeof t=="object"&&t!==null}function K(t){return h(t)&&typeof t.editingSessionId=="string"&&t.editingSessionId.length>0&&typeof t.lockId=="string"&&t.lockId.length>0&&typeof t.ownerId=="string"&&t.ownerId.length>0&&typeof t.leaseAssertion=="string"&&t.leaseAssertion.length>0}function F(t){if(!(!h(t)||typeof t.code!="string"||t.code.length===0))return t.code}function N(t){return t instanceof Error||h(t)&&typeof t.message=="string"&&t.message.length>0?t.message:"Unknown websocket operation failure"}function we(t){try{return g.extractRequestInfo(JSON.parse(t))}catch{return{id:"unknown",kind:"get-document"}}}var H=class{constructor(){this.tail=Promise.resolve()}run(e){let n=this.tail.then(e,e);return this.tail=n.then(()=>{},()=>{}),n}};import{SiteEditOperationRequestSchema as Ae,computeSiteEditCompositionKey as E}from"@vcp-dev/contracts";var He="127.0.0.1",Me=30218,De="/__vcp/site-edit/bridge",ae=6*1024*1024,Ke=ae*2,Fe=3e3,te=50,j=".vcp/current-snapshot.json",ne="__VCP_SITE_EDIT_BRIDGE_SERVERS__";var $=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 H,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.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=$e({server:this.server,path:this.options.path,sessionKey:this.options.sessionKey,host:this.options.host,allowedOrigins:this.options.allowedOrigins,engine:this.bridgeEngine});this.stopWebSocketServer=n.stop}this.stopWatching=new Oe({projectRoot:this.options.projectRoot,watch_dirs:Be(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=We(),n=je(this.options);e.get(n)===this&&e.delete(n),this.isStarted=!1,this.notifyHealthChanged()}notifyHealthChanged(){let e=this.options.onHealthChanged;if(!e)return;let n=this.getHealth(),i=JSON.stringify(n);if(i!==this.lastNotifiedHealth){this.lastNotifiedHealth=i;try{e(n)}catch(o){console.warn(`[vcp-site-edit] onHealthChanged callback failed: ${o instanceof Error?o.message:String(o)}`)}}}createRuntime(e,n=null){let i=this.runtime;this.activeHistoryStore=e??null;let o=(this.dependencies.createRuntime??xe)({...this.options.tenantId?{tenantId:this.options.tenantId}:{},siteId:this.options.siteId,snapshotId:this.options.snapshotId,projectRoot:this.options.projectRoot,compositions:this.compositions,onEvent:s=>{"version"in s&&typeof s.version=="number"&&this.recordRuntimeVersion(s.version,"composition"in s?s.composition:void 0);for(let r of this.eventListeners)r(s)},...e?{historyStore:e}:{},...this.getInitialDocumentVersions().length>0?{initialDocumentVersions:this.getInitialDocumentVersions()}:{}});this.runtime=o,this.activeHistorySessionId=n,i?.dispose(),this.notifyHealthChanged()}createBridgeEngine(){return{resolveComposition:e=>this.resolveComposition(e),initializeSession:e=>this.mutationQueue.run(async()=>{let n=await this.bindHistorySession(this.options.snapshotId);if(!n.ok)throw new Error(`${n.code}: ${n.message}`);let i=Ve(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 p=(await o.getHistoryStatus()).data;return{ok:!0,composition:i,data:{document:a,historyStatus:p}}}),getDocument:async e=>{let n=this.getRuntime(),i=y(e);await n.initializeComposition(i);let o=n.getDocument(i);return await this.recordRuntimeVersion(o.data.version,e),{...o,composition:e}},getHistoryStatus:async e=>({...await this.getRuntime().getHistoryStatus(),composition:e}),getStyleContext:async e=>this.getRuntime().getStyleContext(y(e)),getObjectEditContext:async(e,n,i)=>this.getRuntime().getObjectEditContext(e,y(n),i),getClassNameSource:async(e,n)=>this.getRuntime().getClassNameSource(e,y(n)),getSourceTree:async e=>this.getRuntime().getSourceTree(y(e)),getSourceFile:async e=>this.getRuntime().getSourceFile({path:e.path,composition:y(e.composition)}),resolveSourceLocation:async e=>this.getRuntime().resolveSourceLocation({key:e.key,composition:y(e.composition)}),execute:(e,n)=>this.executeWithReceipt(e,()=>this.mutationQueue.run(async()=>{let i=await this.bindHistorySession(this.options.snapshotId);if(!i.ok)return U(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 U(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 U(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,p]of this.operationReceipts){if(this.operationReceipts.size<=256)break;p.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??be)(Ue({root:this.options.historyRoot,siteId:this.options.siteId,snapshotId:this.options.snapshotId,editingSessionId:e}));if(!this.isStarted)return;let o=i.readDocumentVersion?await i.readDocumentVersion():0,s=this.compositions[0]?.context;if(s){let r=E(s);this.runtimeVersionFloors.set(r,Math.max(this.runtimeVersionFloors.get(r)??0,o))}this.createRuntime(i,e)});this.historySessionTransition=n.catch(()=>{});try{return await n,{ok:!0}}catch{return{ok:!1,code:"RECOVERY_PERSIST_FAILED",message:"Durable edit history could not be opened."}}}recordRuntimeVersion(e,n){let i=n?E(n):null;i&&this.runtimeVersionFloors.set(i,Math.max(this.runtimeVersionFloors.get(i)??0,e));let o=this.activeHistoryStore;if(!o?.writeDocumentVersion)return Promise.resolve();let s=i?this.runtimeVersionFloors.get(i)??e:e;return this.versionPersistence=this.versionPersistence.then(()=>o.writeDocumentVersion(s)).catch(()=>{}),this.versionPersistence}handleFileChanged(e){this.handleFilesChanged([e])}handleFilesChanged(e){for(let i of e)this.pendingChangedFiles.add(i);this.fileChangeTimer&&clearTimeout(this.fileChangeTimer);let n=this.options.runtime.watch_debounce_ms??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(Ze)&&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,j),"utf8"),n=JSON.parse(e),i=typeof n.snapshot_id=="string"?n.snapshot_id:"";return!i||q(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=Pe(this.options.projectRoot),i=Te(n),o=i.length>0?i:(this.options.runtime.routes??[]).map(u=>({...u})),s=ke({files:n});if(s.length===0)throw new Error("No canonical App Router composition is indexed by the preview bridge.");let r=JSON.stringify(s.filter(u=>u.context.effectiveTemplateId!==void 0).map(u=>u.entryFile).sort());if(e&&(this.launchCandidateEntries=r),this.launchCandidateEntries!==r)throw new Error("SITE_EDIT_RUNTIME_RELOAD_REQUIRED: Candidate route collection changed since preview launch");let a=new Map(this.compositions.map(u=>[E(u.context),u])),p=new Map(s.map(u=>[E(u.context),u]));if(this.runtime){for(let[u,l]of a){let S=p.get(u);(!S||S.entryFile!==l.entryFile)&&this.runtime.unregisterComposition(y(l.context))}for(let[u,l]of p){let S=a.get(u);(!S||S.entryFile!==l.entryFile)&&this.runtime.registerComposition(l.context,l.entryFile)}}return this.routes=o,this.compositions=s,this.compositionFiles=n,this.compositionResolutionError=null,this.notifyHealthChanged(),!0}catch(n){let i=n instanceof Error?n:new Error(String(n));if(this.compositionResolutionError=i,e)throw i;return this.notifyHealthChanged(),!1}}resolveComposition(e){if(this.compositionResolutionError)throw this.compositionResolutionError;let n=_e(e.routeId,this.routes,this.options.basePath);if(!n)throw new Error(`Route is not indexed by the preview bridge: ${e.routeId}`);let i=this.routes.find(r=>r.routeId===n);if(!i)throw new Error(`Route is not indexed by the preview bridge: ${e.routeId}`);let o=ve({selector:{routeId:n,...e.templateId!==void 0?{templateId:e.templateId}:{}},files:this.compositionFiles,canonicalEntryFile:i.entryFile}),s=E(o.context);if(!this.compositions.some(r=>E(r.context)===s))throw new Error(`Composition is not registered by the preview bridge: ${s}`);return o}getInitialDocumentVersions(){return this.compositions.flatMap(e=>{let n=this.runtimeVersionFloors.get(E(e.context));return n===void 0?[]:[{composition:e.context,version:n}]})}getRuntime(){if(!this.runtime)throw new Error("VCP site edit preview bridge runtime is not ready");return this.runtime}};function ce(t){let e=new $(Ne(t),oe.createServer(),!1);return e.start({listen:!1,webSocket:!1}),{engine:e.getEngine(),getHealth:()=>e.getHealth(),stop:()=>e.stop()}}function Ne(t){return{tenantId:t.tenantId,siteId:t.siteId,snapshotId:t.snapshotId,projectRoot:m.resolve(t.projectRoot??process.cwd()),basePath:t.basePath??"",host:t.host??He,port:t.port??Me,path:t.path??De,sessionKey:t.sessionKey??Ye(),historyRoot:t.historyRoot,allowedOrigins:t.allowedOrigins??[],runtime:t.runtime??{},onSnapshotIdChanged:t.onSnapshotIdChanged,onHealthChanged:t.onHealthChanged}}function Be(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 Pe(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 p=m.join(s,a.name),u="";try{u=_.readFileSync(p,"utf8")}catch{}e.push({path:m.relative(t,p).replaceAll(m.sep,"/"),content:u})}};for(let s of n)o(m.join(t,s));return e.sort((s,r)=>s.path.localeCompare(r.path))}function Ve(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 Ue(t){return m.join(m.resolve(t.root),q(t.siteId),q(t.snapshotId),J("sha256").update(t.editingSessionId).digest("hex").slice(0,32))}function q(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 We(){let t=globalThis;return t[ne]??=new Map,t[ne]}function je(t){return`${t.projectRoot}:${t.host}:${t.port}:${t.path}:${t.historyRoot??""}`}function U(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 $e(t){let e=new Re({maxPayload:ae,noServer:!0}),n=new WeakSet,i=s=>{new A({socket:new z(s),engine:t.engine,validateOperationRequest:r=>Ae.safeParse(r).success})},o=(s,r,a)=>{if(!qe(s,t))return;let p=ze(s,t);if(!p){r.write(`HTTP/1.1 401 Unauthorized\r
2
2
  Connection: close\r
3
3
  \r
4
- `),r.destroy();return}p.authenticatedByHeader&&n.add(s),e.handleUpgrade(s,r,c,u=>{e.emit("connection",u,s)})};return t.server.on("upgrade",o),e.on("connection",(s,r)=>{if(n.has(r)){i(s);return}Le(s,t.sessionKey,()=>{i(s)})}),e.stop=()=>{t.server.off("upgrade",o);for(let s of e.clients)s.close(1001,"bridge stopped");e.close()},e}var 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")>Ke){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 ze(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"]),o=ue(i,e.sessionKey),s=U(t.headers.host),r=U(t.headers.origin);return s&&!Je(s,e.host,r)?null:r?Ge(r,s,e.allowedOrigins)?{authenticatedByHeader:o}:null:o?{authenticatedByHeader:!0}:null}function Le(t,e,n){let i=setTimeout(()=>{t.close(1008,"bridge authentication timeout")},Ne),o,s=()=>{clearTimeout(i),t.off("message",o),t.off("close",s)},r=()=>{s(),t.close(1008,"bridge authentication failed")};o=c=>{try{let p=g.parseMessage(c.toString());if(p.type!=="auth"||!ue(p.payload.key,e)){r();return}s(),t.readyState===re.OPEN&&t.send(g.stringifyMessage({type:"auth-ok",payload:{ok:!0}})),n()}catch{r()}},t.on("message",o),t.on("close",s)}function ue(t,e){if(!t)return!1;let n=Buffer.from(t),i=Buffer.from(e);return n.length===i.length&&Ee(n,i)}function Je(t,e,n){let i=ie(t),o=ie(e);return i===o||ne(o)&&ne(i)&&(!n||L(n,t))||Qe(o)&&(!n||L(n,t))}function Qe(t){return t==="0.0.0.0"||t==="::"}function ne(t){return t==="localhost"||t==="127.0.0.1"||t==="::1"}function Ge(t,e,n){return n.includes(t)||(e?L(t,e):!1)}function L(t,e){try{return new URL(t).host===de(e)}catch{return!1}}function ie(t){let e=de(t);return e.startsWith("[")?e.slice(1,e.indexOf("]")):e.split(":").length-1===1?e.split(":",1)[0]??"":e}function de(t){return t.trim().toLowerCase()}function U(t){return Array.isArray(t)?t[0]:t}function Ye(){return Ce(32).toString("base64url")}function Ze(t){let e=t.replaceAll("\\","/");return e===W||e.endsWith(`/${W}`)}var R=Xe;if(!R)throw new Error("site edit engine worker must run inside worker_threads");var x=t=>{R.postMessage(t)},tt=(t,e)=>{try{R.postMessage({type:"result",id:t,ok:!0,value:e})}catch(n){if(n instanceof Error&&n.name==="DataCloneError"){R.postMessage({type:"result",id:t,ok:!0,value:e===void 0?void 0:JSON.parse(JSON.stringify(e))});return}throw n}},{options:nt}=et,T;try{T=ce({...nt,onSnapshotIdChanged:(t,e)=>{x({type:"snapshot-id-changed",next:t,previous:e})},onHealthChanged:t=>{x({type:"health",health:t})}})}catch(t){x({type:"start-failed",error:M(t)}),process.exit(1)}T.engine.subscribe(t=>{x({type:"event",event:t})});var it=async t=>{try{let e=T.engine[t.method],n=await e(...t.args);tt(t.id,n)}catch(e){x({type:"result",id:t.id,ok:!1,error:M(e)})}};R.on("message",t=>{if(t.type==="call"){it(t);return}t.type==="stop"&&(T.stop(),R.close())});x({type:"ready",health:T.getHealth()});
4
+ `),r.destroy();return}p.authenticatedByHeader&&n.add(s),e.handleUpgrade(s,r,a,u=>{e.emit("connection",u,s)})};return t.server.on("upgrade",o),e.on("connection",(s,r)=>{if(n.has(r)){i(s);return}Le(s,t.sessionKey,()=>{i(s)})}),e.stop=()=>{t.server.off("upgrade",o);for(let s of e.clients)s.close(1001,"bridge stopped");e.close()},e}var 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")>Ke){this.socket.close(1013,"bridge backpressure");return}this.socket.send(e)}}close(e,n){this.socket.close(e,n)}};function qe(t,e){return new URL(t.url??"/","http://localhost").pathname===e.path}function ze(t,e){if(new URL(t.url??"/","http://localhost").searchParams.has("vcp_bridge_key"))return null;let i=W(t.headers["x-vcp-site-edit-key"]),o=ue(i,e.sessionKey),s=W(t.headers.host),r=W(t.headers.origin);return s&&!Je(s,e.host,r)?null:r?Ge(r,s,e.allowedOrigins)?{authenticatedByHeader:o}:null:o?{authenticatedByHeader:!0}:null}function Le(t,e,n){let i=setTimeout(()=>{t.close(1008,"bridge authentication timeout")},Fe),o,s=()=>{clearTimeout(i),t.off("message",o),t.off("close",s)},r=()=>{s(),t.close(1008,"bridge authentication failed")};o=a=>{try{let p=g.parseMessage(a.toString());if(p.type!=="auth"||!ue(p.payload.key,e)){r();return}s(),t.readyState===re.OPEN&&t.send(g.stringifyMessage({type:"auth-ok",payload:{ok:!0}})),n()}catch{r()}},t.on("message",o),t.on("close",s)}function ue(t,e){if(!t)return!1;let n=Buffer.from(t),i=Buffer.from(e);return n.length===i.length&&Ee(n,i)}function Je(t,e,n){let i=se(t),o=se(e);return i===o||ie(o)&&ie(i)&&(!n||L(n,t))||Qe(o)&&(!n||L(n,t))}function Qe(t){return t==="0.0.0.0"||t==="::"}function ie(t){return t==="localhost"||t==="127.0.0.1"||t==="::1"}function Ge(t,e,n){return n.includes(t)||(e?L(t,e):!1)}function L(t,e){try{return new URL(t).host===de(e)}catch{return!1}}function se(t){let e=de(t);return e.startsWith("[")?e.slice(1,e.indexOf("]")):e.split(":").length-1===1?e.split(":",1)[0]??"":e}function de(t){return t.trim().toLowerCase()}function W(t){return Array.isArray(t)?t[0]:t}function Ye(){return Ce(32).toString("base64url")}function Ze(t){let e=t.replaceAll("\\","/");return e===j||e.endsWith(`/${j}`)}var x=Xe;if(!x)throw new Error("site edit engine worker must run inside worker_threads");var R=t=>{x.postMessage(t)},tt=(t,e)=>{try{x.postMessage({type:"result",id:t,ok:!0,value:e})}catch(n){if(n instanceof Error&&n.name==="DataCloneError"){x.postMessage({type:"result",id:t,ok:!0,value:e===void 0?void 0:JSON.parse(JSON.stringify(e))});return}throw n}},{options:nt}=et,T;try{T=ce({...nt,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:M(t)}),process.exit(1)}T.engine.subscribe(t=>{R({type:"event",event:t})});var it=async t=>{try{let e=T.engine[t.method],n=await e(...t.args);tt(t.id,n)}catch(e){R({type:"result",id:t.id,ok:!1,error:M(e)})}};x.on("message",t=>{if(t.type==="call"){it(t);return}t.type==="stop"&&(T.stop(),x.close())});R({type:"ready",health:T.getHealth()});