@vcp-dev/site-edit-bridge 0.10.37 → 0.10.38
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/auto-bootstrap.js +4 -4
- package/dist/client.js +1 -1
- package/dist/index.js +6 -6
- package/package.json +3 -3
package/dist/client.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function A(n){if(!P(n)){if(n.encoding==="segment-trie-v1")throw new Error("Invalid compact render document");return n}let e=new Map,t=n.pageComposition.status==="supported"?n.pageComposition.placementUnitKeys:[],i=new Map(n.dynamicDataSummaries??[]),o=new Map(n.pageCompositionActionScopes??[]),r=a=>{let s=e.get(a);if(s)return s;let c=n.nodes[a];if(!c)throw new Error(`Missing compact document node ${a}`);let[u,d]=c,p=n.tokens[d];if(typeof p!="string")throw new Error(`Missing compact document token ${d}`);let I=`${u===null?"":r(u)}${p}`;return e.set(a,I),I};return{siteId:n.siteId,snapshotId:n.snapshotId,composition:{...n.composition},routeId:n.composition.routeId,version:n.version,pageComposition:n.pageComposition,entries:n.entries.map((a,s)=>{let[c,u,d]=a,p=d===void 0?void 0:t[d];if(d!==void 0&&!p)throw new Error(`Missing page composition unit ${d}`);let I=n.entryParentNodeIds?.[s],x=o.get(s),R=x?.kind==="source-siblings"?{kind:"source-siblings",siblingKeys:x.siblingEntryIndexes.map(D=>{let M=n.entries[D];if(!M)throw new Error(`Missing source sibling entry ${D}`);return r(M[0])})}:x;return{key:r(c),...n.entryParentNodeIds?{parentKey:I===null?null:r(I)}:{},...p?{pageCompositionUnitKey:p}:{},...R?{pageCompositionActionScope:R}:{},operationSummary:j(u),...i.get(s)?{dynamicDataSummary:i.get(s)}:{}}})}}function j(n){return{canUpdateText:(n&1)!==0,canInsertChild:(n&2)!==0,canMove:(n&4)!==0,canRemove:(n&8)!==0}}function P(n){if(typeof n!="object"||n===null)return!1;let e=n;if(e.encoding!=="segment-trie-v1"||typeof e.siteId!="string"||typeof e.snapshotId!="string"||!$(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 t=e.nodes;if(!t.every((s,c)=>Array.isArray(s)&&s.length===2&&(s[0]===null||m(s[0])&&s[0]<c)&&m(s[1])&&s[1]<e.tokens.length)||!e.entries.every(s=>Array.isArray(s)&&(s.length===2||s.length===3)&&m(s[0])&&s[0]<t.length&&m(s[1])&&s[1]<=15&&(s.length===2||m(s[2]))))return!1;let i=e.entryParentNodeIds;if(i!==void 0&&(!Array.isArray(i)||i.length!==e.entries.length||!i.every(s=>s===null||m(s)&&s<t.length)))return!1;let o=e.dynamicDataSummaries,r=e.pageCompositionActionScopes;return(r===void 0||Array.isArray(r)&&r.every(s=>{if(!Array.isArray(s)||s.length!==2||!m(s[0])||s[0]>=e.entries.length||!b(s[1])||!["route-unit","source-siblings","unavailable"].includes(String(s[1].kind)))return!1;let c=s[1];return c.kind!=="source-siblings"||Array.isArray(c.siblingEntryIndexes)&&c.siblingEntryIndexes.length>=2&&c.siblingEntryIndexes.every(u=>m(u)&&u<e.entries.length)&&c.siblingEntryIndexes.includes(s[0])}))&&(o===void 0||Array.isArray(o)&&o.every(s=>Array.isArray(s)&&s.length===2&&m(s[0])&&s[0]<e.entries.length&&b(s[1])))}function b(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function $(n){return!b(n)||typeof n.routeId!="string"?!1:n.effectiveTemplateId===void 0||typeof n.effectiveTemplateId=="string"}function m(n){return typeof n=="number"&&Number.isInteger(n)&&n>=0}var f=class n{constructor(){}static parseMessage(e,t={}){let i=JSON.parse(e);if(!n.isMessage(i,t))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 t=typeof e.payload.id=="string"?e.payload.id:"unknown",i=this.isRequestKind(e.payload.kind)?e.payload.kind:"get-document";return{id:t,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,t={}){return!h(e)||typeof e.type!="string"?!1:e.type==="request"?W(e.payload,t):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==="ping"||e.type==="pong"?h(e.payload)&&typeof e.payload.id=="string":e.type==="auth-ok"&&h(e.payload)&&e.payload.ok===!0}};function W(n,e){if(!h(n)||typeof n.id!="string"||!f.isRequestKind(n.kind))return!1;let t=T(n.composition);switch(n.kind){case"initialize-session":return t&&(n.mutationContext===void 0||w(n.mutationContext));case"get-document":case"get-style-context":return t;case"get-object-edit-context":return typeof n.key=="string"&&t&&L(n.selectionRef);case"get-class-name-source":case"resolve-source-location":return typeof n.key=="string"&&t;case"get-history-status":return t;case"get-source-tree":return t;case"get-source-file":return typeof n.path=="string"&&t;case"execute":case"get-operation-result":return t&&G(n.request)&&(n.request.mutationContext===void 0||w(n.request.mutationContext))&&(e.validateOperationRequest?.(n.request)??!0);case"undo":case"redo":return t&&n.mutationContext===void 0||t&&w(n.mutationContext)}}function L(n){if(n===void 0)return!0;if(!h(n)||typeof n.key!="string"||n.key.length===0)return!1;let e=n.instanceIndex,t=n.instanceCount;return e!==void 0&&(typeof e!="number"||!Number.isInteger(e)||e<0)||t!==void 0&&(typeof t!="number"||!Number.isInteger(t)||t<=0)||typeof e=="number"&&typeof t=="number"&&e>=t?!1:Object.keys(n).every(i=>i==="key"||i==="instanceIndex"||i==="instanceCount")}function G(n){return h(n)&&typeof n.id=="string"&&typeof n.siteId=="string"&&typeof n.baseSnapshotId=="string"&&T(n.composition)&&typeof n.kind=="string"&&h(n.target)&&(n.target.kind!=="route"||T(n.target.composition))&&typeof n.documentVersion=="number"&&Number.isInteger(n.documentVersion)&&n.documentVersion>=0&&h(n.params)}function T(n){return h(n)&&typeof n.routeId=="string"&&n.routeId.length>0&&(n.templateId===void 0||typeof n.templateId=="string"&&n.templateId.length>0)&&Object.keys(n).every(e=>e==="routeId"||e==="templateId")}function h(n){return typeof n=="object"&&n!==null}function w(n){return h(n)&&typeof n.editingSessionId=="string"&&n.editingSessionId.length>0&&typeof n.lockId=="string"&&n.lockId.length>0&&typeof n.ownerId=="string"&&n.ownerId.length>0&&typeof n.leaseAssertion=="string"&&n.leaseAssertion.length>0}var z="vcp:designer:trace",V="designer_trace",O="__VCP_DESIGNER_TRACE__";var J=/(authorization|cookie|token|secret|providerTrace|headers?|sourceCode|rawSource|fullSource)/i;function H(n=globalThis){let e=n;try{if(e.localStorage?.getItem(z)==="1")return!0}catch{}try{let t=e.location?.search??"";return new URLSearchParams(t).get(V)==="1"}catch{return!1}}function l(n,e={},t=globalThis){if(!H(t))return;let i={type:n,timestamp:Date.now(),payload:Q(e)},o=t,r=o[O]??[];r.push(i),r.length>1e3&&r.splice(0,r.length-1e3),o[O]=r;let a=t.console?.debug;i.payload.diagnosticOnly!==!0&&typeof a=="function"&&a.call(t.console,"[designer-trace]",i)}function Q(n){return k(n,0)}function k(n,e){if(e>4)return"[truncated]";if(Array.isArray(n))return n.map(i=>k(i,e+1));if(!n||typeof n!="object")return n;let t={};for(let[i,o]of Object.entries(n)){if(J.test(i)){t[i]="[redacted]";continue}t[i]=k(o,e+1)}return t}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.heartbeatState=null,this.connectionStatusListeners=new Set}connect(){return this.socket?.readyState===_&&this.connectionState==="open"?(this.setConnectionState("open"),Promise.resolve()):this.connectPromise?this.connectPromise:(this.intentionalClose=!1,this.setConnectionState("connecting"),this.connectPromise=new Promise((e,t)=>{let i;try{i=this.createSocket(this.options.url)}catch(c){let u=y(c,"WebSocket failed");this.socket=null,this.connectAttempt=null,this.connectPromise=null,this.setConnectionState("failed",u.message),t(u);return}let o={socket:i,settled:!1,reject:t};this.connectAttempt=o,this.socket=i;let r=Math.max(0,this.options.connectTimeoutMs??Z);r>0&&(o.deadline=setTimeout(()=>{this.connectAttempt!==o||o.settled||(l("bridge.connect-timeout",{connectTimeoutMs:r}),this.cleanupSocket(i,N(ee,`Bridge connection did not complete within ${r}ms`),"failed"))},r));let a=()=>{this.socket!==i||this.connectAttempt!==o||(o.settled=!0,clearTimeout(o.deadline),this.connectAttempt=null,this.connectPromise=null,this.setConnectionState("open"),this.startHeartbeat(i),e())},s=(c,u)=>{this.cleanupSocket(i,c,u)};i.onopen=()=>{if(!(this.socket!==i||this.connectAttempt!==o)){if(this.options.authKey){try{i.send(f.stringifyMessage({type:"auth",payload:{key:this.options.authKey}}))}catch(c){s(y(c,"WebSocket auth failed"),"failed")}return}a()}},i.onerror=c=>{if(this.socket!==i)return;let u=y(c,"WebSocket failed");s(u,"failed")},i.onmessage=c=>{if(this.socket===i){if(this.noteInboundMessage(i),this.options.authKey&&this.connectAttempt===o&&!o.settled){this.handleAuthHandshakeMessage(c.data,i,o,()=>{a()});return}this.handleMessage(c.data)}},i.onclose=c=>{if(this.socket!==i)return;let u=this.intentionalClose,d=new Error(se(c,{intentional:u}));s(d,u?"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 t=this.selector(e);return this.request("get-document",{composition:t})}async initializeSession(e){let t=this.selector(e.composition);return await this.request("initialize-session",{composition:t,...e.mutationContext?{mutationContext:e.mutationContext}:{}})}getHistoryStatus(e){return this.request("get-history-status",{composition:this.selector(e)})}getStyleContext(e){let t=this.selector(e);return this.request("get-style-context",{composition:t})}getObjectEditContext(e,t,i){let o=this.selector(t);return this.request("get-object-edit-context",{key:e,composition:o,...i?{selectionRef:i}:{}})}getClassNameSource(e,t){let i=this.selector(t);return this.request("get-class-name-source",{key:e,composition:i})}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,t){let i=S(e),o={...e,composition:g(i)};return this.request("execute",{request:o})}getOperationResult(e){return this.request("get-operation-result",{request:e,composition:g(S(e))})}undo(e,t){return this.request("undo",{composition:this.selector(e)})}redo(e,t){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,t){let i=this.socket;if(!i||i.readyState!==_||this.connectionState!=="open")return Promise.reject(new Error(`WebSocket is not open (state: ${this.connectionState}, readyState: ${i?.readyState??"none"})`));let o=`${e}-${this.sequence+=1}`,r=ue(o,e,t);return l("bridge.request",{id:o,kind:e,routeId:typeof t.routeId=="string"?t.routeId:null,key:typeof t.key=="string"?t.key:null,operationKind:K(t.request,"kind"),documentVersion:K(t.request,"documentVersion")}),new Promise((a,s)=>{let c=this.resolveRequestTimeoutMs(e),u=c>0?setTimeout(()=>{let d=this.pending.get(o);d&&(this.pending.delete(o),l("bridge.response",{id:o,kind:e,ok:!1,timedOut:!0}),d.reject(new Error(`Bridge request timed out after ${c}ms: ${e}`)))},c):null;u?.unref?.(),this.pending.set(o,{kind:e,timeout:u,resolve:d=>a(d),reject:s});try{i.send(f.stringifyMessage(r))}catch(d){let p=y(d,"WebSocket send failed");this.clearPendingRequest(o),s(p),this.cleanupSocket(i,p,"failed")}})}handleAuthHandshakeMessage(e,t,i,o){try{if(f.parseMessage(e).type==="auth-ok"){o();return}throw new Error("Bridge authentication failed")}catch(r){let a=y(r,"Bridge authentication failed");this.connectAttempt===i&&this.cleanupSocket(t,a,"failed")}}handleMessage(e){let t=f.parseMessage(e);if(t.type==="event"){for(let o of this.listeners)o(t.payload.event);return}if(t.type!=="response"&&t.type!=="error")return;let i=this.pending.get(t.payload.id);if(i){if(this.clearPendingRequest(t.payload.id),t.type==="error"){l("bridge.response",{id:t.payload.id,kind:i.kind,ok:!1});let o=new Error(t.payload.message);t.payload.code&&(o.code=t.payload.code),i.reject(o);return}l("bridge.response",{id:t.payload.id,kind:i.kind,ok:!0,resultVersion:re(t.payload.result)}),i.resolve(i.kind==="get-document"?{...t.payload.result,data:U(t.payload.result.data,t.payload.result.composition)}:i.kind==="initialize-session"?ce(t.payload.result):t.payload.result)}}rejectAll(e){for(let[t,i]of[...this.pending])this.clearPendingRequest(t),i.reject(e)}clearPendingRequest(e){let t=this.pending.get(e);t&&(t.timeout&&clearTimeout(t.timeout),this.pending.delete(e))}resolveRequestTimeoutMs(e){let t=this.options.requestTimeoutMsByKind?.[e];return typeof t=="number"?Math.max(0,t):typeof this.options.requestTimeoutMs=="number"?Math.max(0,this.options.requestTimeoutMs):oe[e]??ie}cleanupSocket(e,t,i){if(this.socket===e&&(this.socket=null),this.stopHeartbeat(e),this.connectAttempt?.socket===e){let o=this.connectAttempt;this.connectAttempt=null,clearTimeout(o.deadline),o.settled||(o.settled=!0,o.reject(t))}this.connectPromise=null,this.rejectAll(t),this.setConnectionState(i,t.message),e.onopen=null,e.onmessage=null,e.onerror=null,e.onclose=null;try{(e.readyState===Y||e.readyState===_)&&e.close()}catch{}}startHeartbeat(e){let t=this.options.heartbeat===void 0?X:this.options.heartbeat;if(!t||t.intervalMs<=0||t.timeoutMs<=0)return;this.stopHeartbeat(this.heartbeatState?.socket??e);let i=this.options.visibility===void 0?ne():this.options.visibility,o=()=>i?.visibilityState!=="hidden",r=()=>{this.heartbeatState?.socket===e&&this.heartbeatState.deadline&&(clearTimeout(this.heartbeatState.deadline),this.heartbeatState.deadline=null)},a=()=>{let c=this.heartbeatState;if(!(c?.socket!==e||this.socket!==e||this.connectionState!=="open"||c.deadline||!o())){try{e.send(f.stringifyMessage({type:"ping",payload:{id:`ping-${this.sequence+=1}`}}))}catch(u){this.cleanupSocket(e,y(u,"WebSocket heartbeat send failed"),"failed");return}c.deadline=setTimeout(()=>{this.heartbeatState?.socket===e&&(this.heartbeatState.deadline=null,o()&&(l("bridge.heartbeat-timeout",{timeoutMs:t.timeoutMs}),this.cleanupSocket(e,N(te,`Bridge heartbeat was not answered within ${t.timeoutMs}ms`),"failed")))},t.timeoutMs)}},s=()=>{o()?a():r()};i?.addEventListener("visibilitychange",s),this.heartbeatState={socket:e,interval:setInterval(a,t.intervalMs),deadline:null,unbindVisibility:()=>i?.removeEventListener("visibilitychange",s)}}stopHeartbeat(e){let t=this.heartbeatState;!t||t.socket!==e||(clearInterval(t.interval),t.deadline&&clearTimeout(t.deadline),t.unbindVisibility(),this.heartbeatState=null)}noteInboundMessage(e){let t=this.heartbeatState;t?.socket===e&&t.deadline&&(clearTimeout(t.deadline),t.deadline=null)}setConnectionState(e,t){if(this.connectionState===e&&!t)return;this.connectionState=e;let i={state:e,...t?{message:t}:{}};this.options.onConnectionStatus?.(i);for(let o of this.connectionStatusListeners)o(i)}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)}},Y=0,_=1,Z=1e4,X={intervalMs:2e4,timeoutMs:1e4},ee="SITE_EDIT_BRIDGE_CONNECT_TIMEOUT",te="SITE_EDIT_BRIDGE_HEARTBEAT_TIMEOUT";function ne(){let n=globalThis.document;return n&&typeof n.visibilityState=="string"&&typeof n.addEventListener=="function"&&typeof n.removeEventListener=="function"?n:null}function N(n,e){let t=new Error(`${n}: ${e}`);return t.code=n,t}var ie=15e3,oe={"get-source-tree":1e4,"get-source-file":1e4,"resolve-source-location":1e4,execute:6e4,"get-operation-result":6e4,undo:2e4,redo:2e4};function y(n,e){return n instanceof Error?n:new Error(e)}function se(n,e){return e.intentional?"WebSocket disconnected":n?.code===1008?n.reason?`Bridge session authentication failed: ${n.reason}`:"Bridge session authentication failed":n?.reason?`WebSocket closed: ${n.reason}`:typeof n?.code=="number"&&n.code!==1005?`WebSocket closed with code ${n.code}`:"WebSocket closed"}function K(n,e){if(!n||typeof n!="object")return null;let i=n[e];return typeof i=="string"||typeof i=="number"?i:null}function re(n){if(!n||typeof n!="object")return null;let e=n,t=e.data?.resultVersion??e.data?.version??null;return typeof t=="number"?t:null}function Ie(n){let e="composition"in n?g(n.composition):g({routeId:n.routeId});return new q({composition:e,initialDocument:n.initialDocument,client:n.client})}var q=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 t=e.initialDocument.composition.effectiveTemplateId;if(t!==void 0&&(this.composition.templateId===void 0||this.composition.templateId!==t))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=!B(e.initialDocument),this.activeCompositionContext=this.sessionInitialized?{...e.initialDocument.composition}:null}async getDocument(e){this.requireBoundComposition(e);let t=B(this.currentDocument)||this.snapshotIdentityStale;return(t||this.currentDocument.version<this.observedDocumentVersion)&&(this.currentDocument=await this.refreshSnapshot(t?void 0:this.observedDocumentVersion,"get-document"),this.snapshotIdentityStale=!1,this.sessionInitialized=!0),{ok:!0,data:this.currentDocument}}async initializeSession(e){let t=this.requireBoundComposition(e.composition);if(!this.params.client.initializeSession)throw new Error("Site edit bridge client does not support initialize-session");let i=await this.params.client.initializeSession({...e,composition:t});return this.currentDocument=i.data.document,this.observedDocumentVersion=i.data.document.version,this.activeCompositionContext={...i.composition},this.rememberServerConfirmedComposition(i.composition),this.sessionInitialized=!0,this.clearObjectCaches(),i}async getHistoryStatus(e){return this.params.client.getHistoryStatus(this.requireBoundComposition(e))}async getStyleContext(e){let t=this.requireBoundComposition(e),i=C(t),o=this.styleContextCache.get(i);if(o?.generation===this.styleGeneration)return{ok:!0,data:o.value};let r=this.styleContextInFlight.get(i);if(r?.generation===this.styleGeneration)return r.request;let a=this.styleGeneration,s=this.params.client.getStyleContext(t).then(c=>(this.styleGeneration===a&&this.styleContextCache.set(i,{generation:a,value:c.data}),c)).finally(()=>{this.styleContextInFlight.get(i)?.request===s&&this.styleContextInFlight.delete(i)});return this.styleContextInFlight.set(i,{generation:a,request:s}),s}async ensureDocumentVersion(e,t){this.requireBoundComposition(e);let i=await this.refreshSnapshot(t,"ensure-version");if(i.version<t)throw new Error(`Document refresh returned version ${i.version}, expected at least ${t}`);return{ok:!0,data:i}}async acknowledgeDocumentVersion(e,t){if(this.requireBoundComposition(e),t>this.currentDocument.version){if(this.currentDocument.pageComposition.status==="supported"){let i=await this.refreshSnapshot(t,"ensure-version");if(i.version<t)throw new Error(`Document refresh returned version ${i.version}, expected at least ${t}`);return{ok:!0,data:i}}this.currentDocument={...this.currentDocument,version:t},this.clearObjectCaches({preserveStyleContext:!0})}return this.observedDocumentVersion=Math.max(this.observedDocumentVersion,t),{ok:!0,data:this.currentDocument}}async getObjectEditContext(e,t,i){let o=this.requireBoundComposition(t),r=this.objectCacheKey(e,o,i),a=this.editContextCache.get(r);if(a)return{ok:!0,data:a};let s=this.editContextInFlight.get(r);if(s)return s;let c=this.objectGeneration,u=this.params.client.getObjectEditContext(e,o,...i?[i]:[]).then(d=>(this.objectGeneration===c&&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,t){let i=this.requireBoundComposition(t),o=this.objectCacheKey(e,i),r=this.classNameSourceCache.get(o);if(r)return r;let a=this.classNameSourceInFlight.get(o);if(a)return a;let s=this.objectGeneration,c=this.params.client.getClassNameSource(e,i).then(u=>(this.objectGeneration===s&&this.classNameSourceCache.set(o,u),u)).finally(()=>{this.classNameSourceInFlight.get(o)===c&&this.classNameSourceInFlight.delete(o)});return this.classNameSourceInFlight.set(o,c),c}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,t){let i=S(e);i&&this.composition.templateId!==void 0&&this.requireBoundComposition(i);let o={...e,composition:i??this.composition};return this.params.client.execute(o)}async getOperationResult(e){return this.requireBoundComposition(e.composition),this.params.client.getOperationResult?this.params.client.getOperationResult(e):null}async undo(e,t){return this.params.client.undo(this.requireBoundComposition(e))}async redo(e,t){return this.params.client.redo(this.requireBoundComposition(e))}subscribe(e){return this.params.client.subscribe(t=>{if(t.type==="site-edit.snapshot.changed"&&this.sessionInitialized&&this.isActiveComposition(t.composition)){this.snapshotIdentityStale=!0,this.clearObjectCaches(),e(t);return}if(t.type==="site-edit.document.changed"&&this.sessionInitialized&&this.isActiveComposition(t.composition)){this.observedDocumentVersion=Math.max(this.observedDocumentVersion,t.version),t.version>this.currentDocument.version&&this.clearObjectCaches(),e(t);return}e(t)})}async refreshSnapshot(e,t="ensure-version"){if(typeof e=="number"&&this.currentDocument.version>=e)return l("bridge.document-refresh",{composition:this.composition,routeId:this.composition.routeId,minVersion:e,currentVersion:this.currentDocument.version,deduped:!0,skipped:!0,source:t}),this.currentDocument;let i=C(this.composition),o=this.refreshInFlight;if(o?.compositionKey===i){l("bridge.document-refresh",{composition:this.composition,routeId:this.composition.routeId,minVersion:e,currentVersion:this.currentDocument.version,deduped:!0,source:t});let a=await o.request;if(typeof e!="number"||a.version>=e||this.currentDocument.version>=e)return this.currentDocument}l("bridge.document-refresh",{composition:this.composition,routeId:this.composition.routeId,minVersion:e,currentVersion:this.currentDocument.version,deduped:!1,source:t});let r=this.params.client.getDocument(this.composition).then(a=>(this.currentDocument=a.data,this.activeCompositionContext={...a.data.composition},this.rememberServerConfirmedComposition(a.data.composition),this.observedDocumentVersion=Math.max(this.observedDocumentVersion,a.data.version),this.clearObjectCaches(),this.currentDocument));this.refreshInFlight={compositionKey:i,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,t,i){return`${C(t)}\0${e}\0${ae(i)}`}rememberServerConfirmedComposition(e){!e||typeof e.routeId!="string"||(this.serverConfirmedComposition={...e})}isAcceptedComposition(e){if(C(e)===C(this.composition))return!0;let t=this.serverConfirmedComposition;return t!==null&&E(t)===E(F(e))}requireBoundComposition(e){let t=e===void 0?this.composition:g(e);if(!this.isAcceptedComposition(t))throw new Error(`Site edit bridge is bound to composition ${JSON.stringify(this.composition)}, received ${JSON.stringify(t)}`);return g(t)}isActiveComposition(e){let t=this.activeCompositionContext??F(this.composition);return E(e)===E(t)}};function B(n){return n.version===0&&n.entries.length===0}function ce(n){let e=n;return{...e,data:{...e.data,document:U(e.data.document,e.composition)}}}function U(n,e){let t=n,i=A(t.routeId?t:{...t,routeId:e?.routeId??t.composition?.routeId});return e?{...i,composition:e}:i}function g(n){if(n&&typeof n=="object"&&typeof n.routeId=="string"){let e="effectiveTemplateId"in n?n.effectiveTemplateId:"templateId"in n?n.templateId:void 0;return{routeId:n.routeId,...typeof e=="string"?{templateId:e}:{}}}throw new Error("SITE_EDIT_COMPOSITION_SESSION_REQUIRED: a composition selector is required")}function C(n){return JSON.stringify([n.routeId,n.templateId??null])}function ae(n){return n?JSON.stringify([n.key,n.instanceIndex??null,n.instanceCount??null]):""}function E(n){return JSON.stringify([n.routeId,n.effectiveTemplateId??null])}function F(n){return{routeId:n.routeId,...n.templateId?{effectiveTemplateId:n.templateId}:{}}}function S(n){if(n&&typeof n=="object"){let e=n;if(e.composition&&typeof e.composition=="object"){let t=e.composition;if(typeof t.routeId=="string")return{routeId:t.routeId,...typeof t.templateId=="string"?{templateId:t.templateId}:{}}}}}function ue(n,e,t){let i=g(e==="execute"?S(t.request):t.composition),o={id:n,kind:e,composition:i};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:{...o,...t.mutationContext?{mutationContext:t.mutationContext}:{}}};case"get-object-edit-context":return{type:"request",payload:{...o,key:String(t.key),...t.selectionRef?{selectionRef:t.selectionRef}:{}}};case"get-class-name-source":case"resolve-source-location":return{type:"request",payload:{...o,key:String(t.key)}};case"get-source-file":return{type:"request",payload:{...o,path:String(t.path)}};case"execute":case"get-operation-result":return{type:"request",payload:{...o,request:{...t.request,composition:S(t.request)??i}}}}}export{ee as SITE_EDIT_BRIDGE_CONNECT_TIMEOUT,te as SITE_EDIT_BRIDGE_HEARTBEAT_TIMEOUT,v as SiteEditWebSocketClient,Ie as createSiteEditBridge};
|
|
1
|
+
function A(n){if(!P(n)){if(n.encoding==="segment-trie-v1")throw new Error("Invalid compact render document");return n}let e=new Map,t=n.pageComposition.status==="supported"?n.pageComposition.placementUnitKeys:[],i=new Map(n.dynamicDataSummaries??[]),s=new Map(n.pageCompositionActionScopes??[]),r=c=>{let o=e.get(c);if(o)return o;let a=n.nodes[c];if(!a)throw new Error(`Missing compact document node ${c}`);let[u,d]=a,p=n.tokens[d];if(typeof p!="string")throw new Error(`Missing compact document token ${d}`);let C=`${u===null?"":r(u)}${p}`;return e.set(c,C),C};return{siteId:n.siteId,snapshotId:n.snapshotId,composition:{...n.composition},routeId:n.composition.routeId,version:n.version,pageComposition:n.pageComposition,entries:n.entries.map((c,o)=>{let[a,u,d]=c,p=d===void 0?void 0:t[d];if(d!==void 0&&!p)throw new Error(`Missing page composition unit ${d}`);let C=n.entryParentNodeIds?.[o],x=s.get(o),D=x?.kind==="source-siblings"?{kind:"source-siblings",siblingKeys:x.siblingEntryIndexes.map(R=>{let M=n.entries[R];if(!M)throw new Error(`Missing source sibling entry ${R}`);return r(M[0])})}:x;return{key:r(a),...n.entryParentNodeIds?{parentKey:C===null?null:r(C)}:{},...p?{pageCompositionUnitKey:p}:{},...D?{pageCompositionActionScope:D}:{},operationSummary:j(u),...i.get(o)?{dynamicDataSummary:i.get(o)}:{}}})}}function j(n){return{canUpdateText:(n&1)!==0,canInsertChild:(n&2)!==0,canMove:(n&4)!==0,canRemove:(n&8)!==0}}function P(n){if(typeof n!="object"||n===null)return!1;let e=n;if(e.encoding!=="segment-trie-v1"||typeof e.siteId!="string"||typeof e.snapshotId!="string"||!$(e.composition)||typeof e.routeId!="string"||e.routeId!==e.composition.routeId||!Number.isInteger(e.version)||e.version<0||!E(e.pageComposition)||!Array.isArray(e.tokens)||!e.tokens.every(o=>typeof o=="string")||!Array.isArray(e.nodes)||!Array.isArray(e.entries))return!1;let t=e.nodes;if(!t.every((o,a)=>Array.isArray(o)&&o.length===2&&(o[0]===null||m(o[0])&&o[0]<a)&&m(o[1])&&o[1]<e.tokens.length)||!e.entries.every(o=>Array.isArray(o)&&(o.length===2||o.length===3)&&m(o[0])&&o[0]<t.length&&m(o[1])&&o[1]<=15&&(o.length===2||m(o[2]))))return!1;let i=e.entryParentNodeIds;if(i!==void 0&&(!Array.isArray(i)||i.length!==e.entries.length||!i.every(o=>o===null||m(o)&&o<t.length)))return!1;let s=e.dynamicDataSummaries,r=e.pageCompositionActionScopes;return(r===void 0||Array.isArray(r)&&r.every(o=>{if(!Array.isArray(o)||o.length!==2||!m(o[0])||o[0]>=e.entries.length||!E(o[1])||!["route-unit","source-siblings","unavailable"].includes(String(o[1].kind)))return!1;let a=o[1];return a.kind!=="source-siblings"||Array.isArray(a.siblingEntryIndexes)&&a.siblingEntryIndexes.length>=2&&a.siblingEntryIndexes.every(u=>m(u)&&u<e.entries.length)&&a.siblingEntryIndexes.includes(o[0])}))&&(s===void 0||Array.isArray(s)&&s.every(o=>Array.isArray(o)&&o.length===2&&m(o[0])&&o[0]<e.entries.length&&E(o[1])))}function E(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function $(n){return!E(n)||typeof n.routeId!="string"?!1:n.effectiveTemplateId===void 0||typeof n.effectiveTemplateId=="string"}function m(n){return typeof n=="number"&&Number.isInteger(n)&&n>=0}var f=class n{constructor(){}static parseMessage(e,t={}){let i=JSON.parse(e);if(!n.isMessage(i,t))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 t=typeof e.payload.id=="string"?e.payload.id:"unknown",i=this.isRequestKind(e.payload.kind)?e.payload.kind:"get-document";return{id:t,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,t={}){return!h(e)||typeof e.type!="string"?!1:e.type==="request"?W(e.payload,t):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==="ping"||e.type==="pong"?h(e.payload)&&typeof e.payload.id=="string":e.type==="auth-ok"&&h(e.payload)&&e.payload.ok===!0}};function W(n,e){if(!h(n)||typeof n.id!="string"||!f.isRequestKind(n.kind))return!1;let t=T(n.composition);switch(n.kind){case"initialize-session":return t&&(n.mutationContext===void 0||w(n.mutationContext));case"get-document":case"get-style-context":return t;case"get-object-edit-context":return typeof n.key=="string"&&t&&L(n.selectionRef);case"get-class-name-source":case"resolve-source-location":return typeof n.key=="string"&&t;case"get-history-status":return t;case"get-source-tree":return t;case"get-source-file":return typeof n.path=="string"&&t;case"execute":case"get-operation-result":return t&&V(n.request)&&(n.request.mutationContext===void 0||w(n.request.mutationContext))&&(e.validateOperationRequest?.(n.request)??!0);case"undo":case"redo":return t&&n.mutationContext===void 0||t&&w(n.mutationContext)}}function L(n){if(n===void 0)return!0;if(!h(n)||typeof n.key!="string"||n.key.length===0)return!1;let e=n.instanceIndex,t=n.instanceCount;return e!==void 0&&(typeof e!="number"||!Number.isInteger(e)||e<0)||t!==void 0&&(typeof t!="number"||!Number.isInteger(t)||t<=0)||typeof e=="number"&&typeof t=="number"&&e>=t?!1:Object.keys(n).every(i=>i==="key"||i==="instanceIndex"||i==="instanceCount")}function V(n){return h(n)&&typeof n.id=="string"&&typeof n.siteId=="string"&&typeof n.baseSnapshotId=="string"&&T(n.composition)&&typeof n.kind=="string"&&h(n.target)&&(n.target.kind!=="route"||T(n.target.composition))&&typeof n.documentVersion=="number"&&Number.isInteger(n.documentVersion)&&n.documentVersion>=0&&h(n.params)}function T(n){return h(n)&&typeof n.routeId=="string"&&n.routeId.length>0&&(n.templateId===void 0||typeof n.templateId=="string"&&n.templateId.length>0)&&Object.keys(n).every(e=>e==="routeId"||e==="templateId")}function h(n){return typeof n=="object"&&n!==null}function w(n){return h(n)&&typeof n.editingSessionId=="string"&&n.editingSessionId.length>0&&typeof n.lockId=="string"&&n.lockId.length>0&&typeof n.ownerId=="string"&&n.ownerId.length>0&&typeof n.leaseAssertion=="string"&&n.leaseAssertion.length>0}var G="vcp:designer:trace",z="designer_trace",v="__VCP_DESIGNER_TRACE__";var J=/(authorization|cookie|token|secret|providerTrace|headers?|sourceCode|rawSource|fullSource)/i;function H(n=globalThis){let e=n;try{if(e.localStorage?.getItem(G)==="1")return!0}catch{}try{let t=e.location?.search??"";return new URLSearchParams(t).get(z)==="1"}catch{return!1}}function l(n,e={},t=globalThis){if(!H(t))return;let i={type:n,timestamp:Date.now(),payload:Q(e)},s=t,r=s[v]??[];r.push(i),r.length>1e3&&r.splice(0,r.length-1e3),s[v]=r;let c=t.console?.debug;i.payload.diagnosticOnly!==!0&&typeof c=="function"&&c.call(t.console,"[designer-trace]",i)}function Q(n){return k(n,0)}function k(n,e){if(e>4)return"[truncated]";if(Array.isArray(n))return n.map(i=>k(i,e+1));if(!n||typeof n!="object")return n;let t={};for(let[i,s]of Object.entries(n)){if(J.test(i)){t[i]="[redacted]";continue}t[i]=k(s,e+1)}return t}var O=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.heartbeatState=null,this.connectionStatusListeners=new Set}connect(){return this.socket?.readyState===_&&this.connectionState==="open"?(this.setConnectionState("open"),Promise.resolve()):this.connectPromise?this.connectPromise:(this.intentionalClose=!1,this.setConnectionState("connecting"),this.connectPromise=new Promise((e,t)=>{let i;try{i=this.createSocket(this.options.url)}catch(a){let u=y(a,"WebSocket failed");this.socket=null,this.connectAttempt=null,this.connectPromise=null,this.setConnectionState("failed",u.message),t(u);return}let s={socket:i,settled:!1,reject:t};this.connectAttempt=s,this.socket=i;let r=Math.max(0,this.options.connectTimeoutMs??Z);r>0&&(s.deadline=setTimeout(()=>{this.connectAttempt!==s||s.settled||(l("bridge.connect-timeout",{connectTimeoutMs:r}),this.cleanupSocket(i,N(ee,`Bridge connection did not complete within ${r}ms`),"failed"))},r));let c=()=>{this.socket!==i||this.connectAttempt!==s||(s.settled=!0,clearTimeout(s.deadline),this.connectAttempt=null,this.connectPromise=null,this.setConnectionState("open"),this.startHeartbeat(i),e())},o=(a,u)=>{this.cleanupSocket(i,a,u)};i.onopen=()=>{if(!(this.socket!==i||this.connectAttempt!==s)){if(this.options.authKey){try{i.send(f.stringifyMessage({type:"auth",payload:{key:this.options.authKey}}))}catch(a){o(y(a,"WebSocket auth failed"),"failed")}return}c()}},i.onerror=a=>{if(this.socket!==i)return;let u=y(a,"WebSocket failed");o(u,"failed")},i.onmessage=a=>{if(this.socket===i){if(this.noteInboundMessage(i),this.options.authKey&&this.connectAttempt===s&&!s.settled){this.handleAuthHandshakeMessage(a.data,i,s,()=>{c()});return}this.handleMessage(a.data)}},i.onclose=a=>{if(this.socket!==i)return;let u=this.intentionalClose,d=new Error(oe(a,{intentional:u}));o(d,u?"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 t=this.selector(e);return this.request("get-document",{composition:t})}async initializeSession(e){let t=this.selector(e.composition);return await this.request("initialize-session",{composition:t,...e.mutationContext?{mutationContext:e.mutationContext}:{}})}getHistoryStatus(e){return this.request("get-history-status",{composition:this.selector(e)})}getStyleContext(e){let t=this.selector(e);return this.request("get-style-context",{composition:t})}getObjectEditContext(e,t,i){let s=this.selector(t);return this.request("get-object-edit-context",{key:e,composition:s,...i?{selectionRef:i}:{}})}getClassNameSource(e,t){let i=this.selector(t);return this.request("get-class-name-source",{key:e,composition:i})}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,t){let i=b(e),s={...e,composition:g(i)};return this.request("execute",{request:s})}getOperationResult(e){return this.request("get-operation-result",{request:e,composition:g(b(e))})}undo(e,t){return this.request("undo",{composition:this.selector(e)})}redo(e,t){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,t){let i=this.socket;if(!i||i.readyState!==_||this.connectionState!=="open")return Promise.reject(new Error(`WebSocket is not open (state: ${this.connectionState}, readyState: ${i?.readyState??"none"})`));let s=`${e}-${this.sequence+=1}`,r=ue(s,e,t);return l("bridge.request",{id:s,kind:e,routeId:typeof t.routeId=="string"?t.routeId:null,key:typeof t.key=="string"?t.key:null,operationKind:K(t.request,"kind"),documentVersion:K(t.request,"documentVersion")}),new Promise((c,o)=>{let a=this.resolveRequestTimeoutMs(e),u=a>0?setTimeout(()=>{let d=this.pending.get(s);d&&(this.pending.delete(s),l("bridge.response",{id:s,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(s,{kind:e,timeout:u,resolve:d=>c(d),reject:o});try{i.send(f.stringifyMessage(r))}catch(d){let p=y(d,"WebSocket send failed");this.clearPendingRequest(s),o(p),this.cleanupSocket(i,p,"failed")}})}handleAuthHandshakeMessage(e,t,i,s){try{if(f.parseMessage(e).type==="auth-ok"){s();return}throw new Error("Bridge authentication failed")}catch(r){let c=y(r,"Bridge authentication failed");this.connectAttempt===i&&this.cleanupSocket(t,c,"failed")}}handleMessage(e){let t=f.parseMessage(e);if(t.type==="event"){for(let s of this.listeners)s(t.payload.event);return}if(t.type!=="response"&&t.type!=="error")return;let i=this.pending.get(t.payload.id);if(i){if(this.clearPendingRequest(t.payload.id),t.type==="error"){l("bridge.response",{id:t.payload.id,kind:i.kind,ok:!1});let s=new Error(t.payload.message);t.payload.code&&(s.code=t.payload.code),i.reject(s);return}l("bridge.response",{id:t.payload.id,kind:i.kind,ok:!0,resultVersion:re(t.payload.result)}),i.resolve(i.kind==="get-document"?{...t.payload.result,data:U(t.payload.result.data,t.payload.result.composition)}:i.kind==="initialize-session"?ce(t.payload.result):t.payload.result)}}rejectAll(e){for(let[t,i]of[...this.pending])this.clearPendingRequest(t),i.reject(e)}clearPendingRequest(e){let t=this.pending.get(e);t&&(t.timeout&&clearTimeout(t.timeout),this.pending.delete(e))}resolveRequestTimeoutMs(e){let t=this.options.requestTimeoutMsByKind?.[e];return typeof t=="number"?Math.max(0,t):typeof this.options.requestTimeoutMs=="number"?Math.max(0,this.options.requestTimeoutMs):se[e]??ie}cleanupSocket(e,t,i){if(this.socket===e&&(this.socket=null),this.stopHeartbeat(e),this.connectAttempt?.socket===e){let s=this.connectAttempt;this.connectAttempt=null,clearTimeout(s.deadline),s.settled||(s.settled=!0,s.reject(t))}this.connectPromise=null,this.rejectAll(t),this.setConnectionState(i,t.message),e.onopen=null,e.onmessage=null,e.onerror=null,e.onclose=null;try{(e.readyState===Y||e.readyState===_)&&e.close()}catch{}}startHeartbeat(e){let t=this.options.heartbeat===void 0?X:this.options.heartbeat;if(!t||t.intervalMs<=0||t.timeoutMs<=0)return;this.stopHeartbeat(this.heartbeatState?.socket??e);let i=this.options.visibility===void 0?ne():this.options.visibility,s=()=>i?.visibilityState!=="hidden",r=()=>{this.heartbeatState?.socket===e&&this.heartbeatState.deadline&&(clearTimeout(this.heartbeatState.deadline),this.heartbeatState.deadline=null)},c=()=>{let a=this.heartbeatState;if(!(a?.socket!==e||this.socket!==e||this.connectionState!=="open"||a.deadline||!s())){try{e.send(f.stringifyMessage({type:"ping",payload:{id:`ping-${this.sequence+=1}`}}))}catch(u){this.cleanupSocket(e,y(u,"WebSocket heartbeat send failed"),"failed");return}a.deadline=setTimeout(()=>{this.heartbeatState?.socket===e&&(this.heartbeatState.deadline=null,s()&&(l("bridge.heartbeat-timeout",{timeoutMs:t.timeoutMs}),this.cleanupSocket(e,N(te,`Bridge heartbeat was not answered within ${t.timeoutMs}ms`),"failed")))},t.timeoutMs)}},o=()=>{s()?c():r()};i?.addEventListener("visibilitychange",o),this.heartbeatState={socket:e,interval:setInterval(c,t.intervalMs),deadline:null,unbindVisibility:()=>i?.removeEventListener("visibilitychange",o)}}stopHeartbeat(e){let t=this.heartbeatState;!t||t.socket!==e||(clearInterval(t.interval),t.deadline&&clearTimeout(t.deadline),t.unbindVisibility(),this.heartbeatState=null)}noteInboundMessage(e){let t=this.heartbeatState;t?.socket===e&&t.deadline&&(clearTimeout(t.deadline),t.deadline=null)}setConnectionState(e,t){if(this.connectionState===e&&!t)return;this.connectionState=e;let i={state:e,...t?{message:t}:{}};this.options.onConnectionStatus?.(i);for(let s of this.connectionStatusListeners)s(i)}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)}},Y=0,_=1,Z=1e4,X={intervalMs:2e4,timeoutMs:1e4},ee="SITE_EDIT_BRIDGE_CONNECT_TIMEOUT",te="SITE_EDIT_BRIDGE_HEARTBEAT_TIMEOUT";function ne(){let n=globalThis.document;return n&&typeof n.visibilityState=="string"&&typeof n.addEventListener=="function"&&typeof n.removeEventListener=="function"?n:null}function N(n,e){let t=new Error(`${n}: ${e}`);return t.code=n,t}var ie=15e3,se={"get-source-tree":1e4,"get-source-file":1e4,"resolve-source-location":1e4,execute:6e4,"get-operation-result":6e4,undo:2e4,redo:2e4};function y(n,e){return n instanceof Error?n:new Error(e)}function oe(n,e){return e.intentional?"WebSocket disconnected":n?.code===1008?n.reason?`Bridge session authentication failed: ${n.reason}`:"Bridge session authentication failed":n?.reason?`WebSocket closed: ${n.reason}`:typeof n?.code=="number"&&n.code!==1005?`WebSocket closed with code ${n.code}`:"WebSocket closed"}function K(n,e){if(!n||typeof n!="object")return null;let i=n[e];return typeof i=="string"||typeof i=="number"?i:null}function re(n){if(!n||typeof n!="object")return null;let e=n,t=e.data?.resultVersion??e.data?.version??null;return typeof t=="number"?t:null}function Ie(n){let e="composition"in n?g(n.composition):g({routeId:n.routeId});return new q({composition:e,initialDocument:n.initialDocument,client:n.client})}var q=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 t=e.initialDocument.composition.effectiveTemplateId;if(t!==void 0&&(this.composition.templateId===void 0||this.composition.templateId!==t))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=!B(e.initialDocument),this.activeCompositionContext=this.sessionInitialized?{...e.initialDocument.composition}:null}async getDocument(e){this.requireBoundComposition(e);let t=B(this.currentDocument)||this.snapshotIdentityStale;return(t||this.currentDocument.version<this.observedDocumentVersion)&&(this.currentDocument=await this.refreshSnapshot(t?void 0:this.observedDocumentVersion,"get-document"),this.snapshotIdentityStale=!1,this.sessionInitialized=!0),{ok:!0,data:this.currentDocument}}async initializeSession(e){let t=this.requireBoundComposition(e.composition);if(!this.params.client.initializeSession)throw new Error("Site edit bridge client does not support initialize-session");let i=await this.params.client.initializeSession({...e,composition:t});return this.currentDocument=i.data.document,this.observedDocumentVersion=i.data.document.version,this.activeCompositionContext={...i.composition},this.rememberServerConfirmedComposition(i.composition),this.sessionInitialized=!0,this.clearObjectCaches(),i}async getHistoryStatus(e){return this.params.client.getHistoryStatus(this.requireBoundComposition(e))}async getStyleContext(e){let t=this.requireBoundComposition(e),i=S(t),s=this.styleContextCache.get(i);if(s?.generation===this.styleGeneration)return{ok:!0,data:s.value};let r=this.styleContextInFlight.get(i);if(r?.generation===this.styleGeneration)return r.request;let c=this.styleGeneration,o=this.params.client.getStyleContext(t).then(a=>(this.styleGeneration===c&&this.styleContextCache.set(i,{generation:c,value:a.data}),a)).finally(()=>{this.styleContextInFlight.get(i)?.request===o&&this.styleContextInFlight.delete(i)});return this.styleContextInFlight.set(i,{generation:c,request:o}),o}async ensureDocumentVersion(e,t){this.requireBoundComposition(e);let i=await this.refreshSnapshot(t,"ensure-version");if(i.version<t)throw new Error(`Document refresh returned version ${i.version}, expected at least ${t}`);return{ok:!0,data:i}}async acknowledgeDocumentVersion(e,t){if(this.requireBoundComposition(e),t>this.currentDocument.version){if(this.currentDocument.pageComposition.status==="supported"){let i=await this.refreshSnapshot(t,"ensure-version");if(i.version<t)throw new Error(`Document refresh returned version ${i.version}, expected at least ${t}`);return{ok:!0,data:i}}this.currentDocument={...this.currentDocument,version:t},this.clearObjectCaches({preserveStyleContext:!0})}return this.observedDocumentVersion=Math.max(this.observedDocumentVersion,t),{ok:!0,data:this.currentDocument}}async getObjectEditContext(e,t,i){let s=this.requireBoundComposition(t),r=this.objectCacheKey(e,s,i),c=this.editContextCache.get(r);if(c)return{ok:!0,data:c};let o=this.editContextInFlight.get(r);if(o)return o;let a=this.objectGeneration,u=this.params.client.getObjectEditContext(e,s,...i?[i]:[]).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,t){let i=this.requireBoundComposition(t),s=this.objectCacheKey(e,i),r=this.classNameSourceCache.get(s);if(r)return r;let c=this.classNameSourceInFlight.get(s);if(c)return c;let o=this.objectGeneration,a=this.params.client.getClassNameSource(e,i).then(u=>(this.objectGeneration===o&&this.classNameSourceCache.set(s,u),u)).finally(()=>{this.classNameSourceInFlight.get(s)===a&&this.classNameSourceInFlight.delete(s)});return this.classNameSourceInFlight.set(s,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,t){let i=b(e);i&&this.composition.templateId!==void 0&&this.requireBoundComposition(i);let s={...e,composition:i??this.composition};return this.params.client.execute(s)}async getOperationResult(e){return this.requireBoundComposition(e.composition),this.params.client.getOperationResult?this.params.client.getOperationResult(e):null}async undo(e,t){return this.params.client.undo(this.requireBoundComposition(e))}async redo(e,t){return this.params.client.redo(this.requireBoundComposition(e))}subscribe(e){return this.params.client.subscribe(t=>{if(t.type==="site-edit.snapshot.changed"&&this.sessionInitialized&&this.isActiveComposition(t.composition)){this.snapshotIdentityStale=!0,this.clearObjectCaches(),e(t);return}if(t.type==="site-edit.document.changed"&&this.sessionInitialized&&this.isActiveComposition(t.composition)){let i=t.version>this.observedDocumentVersion;this.observedDocumentVersion=Math.max(this.observedDocumentVersion,t.version),i&&t.version>this.currentDocument.version&&this.clearObjectCaches(),e(t);return}e(t)})}async refreshSnapshot(e,t="ensure-version"){if(typeof e=="number"&&this.currentDocument.version>=e)return l("bridge.document-refresh",{composition:this.composition,routeId:this.composition.routeId,minVersion:e,currentVersion:this.currentDocument.version,deduped:!0,skipped:!0,source:t}),this.currentDocument;let i=S(this.composition),s=this.refreshInFlight;if(s?.compositionKey===i){l("bridge.document-refresh",{composition:this.composition,routeId:this.composition.routeId,minVersion:e,currentVersion:this.currentDocument.version,deduped:!0,source:t});let c=await s.request;if(typeof e!="number"||c.version>=e||this.currentDocument.version>=e)return this.currentDocument}l("bridge.document-refresh",{composition:this.composition,routeId:this.composition.routeId,minVersion:e,currentVersion:this.currentDocument.version,deduped:!1,source:t});let r=this.params.client.getDocument(this.composition).then(c=>{let o=!this.snapshotIdentityStale&&c.data.snapshotId===this.currentDocument.snapshotId&&I(c.data.composition)===I(this.currentDocument.composition)&&c.data.version>this.currentDocument.version&&c.data.version===this.observedDocumentVersion;return this.currentDocument=c.data,this.activeCompositionContext={...c.data.composition},this.rememberServerConfirmedComposition(c.data.composition),this.observedDocumentVersion=Math.max(this.observedDocumentVersion,c.data.version),o||this.clearObjectCaches(),this.currentDocument});this.refreshInFlight={compositionKey:i,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,t,i){return`${S(t)}\0${e}\0${ae(i)}`}rememberServerConfirmedComposition(e){!e||typeof e.routeId!="string"||(this.serverConfirmedComposition={...e})}isAcceptedComposition(e){if(S(e)===S(this.composition))return!0;let t=this.serverConfirmedComposition;return t!==null&&I(t)===I(F(e))}requireBoundComposition(e){let t=e===void 0?this.composition:g(e);if(!this.isAcceptedComposition(t))throw new Error(`Site edit bridge is bound to composition ${JSON.stringify(this.composition)}, received ${JSON.stringify(t)}`);return g(t)}isActiveComposition(e){let t=this.activeCompositionContext??F(this.composition);return I(e)===I(t)}};function B(n){return n.version===0&&n.entries.length===0}function ce(n){let e=n;return{...e,data:{...e.data,document:U(e.data.document,e.composition)}}}function U(n,e){let t=n,i=A(t.routeId?t:{...t,routeId:e?.routeId??t.composition?.routeId});return e?{...i,composition:e}:i}function g(n){if(n&&typeof n=="object"&&typeof n.routeId=="string"){let e="effectiveTemplateId"in n?n.effectiveTemplateId:"templateId"in n?n.templateId:void 0;return{routeId:n.routeId,...typeof e=="string"?{templateId:e}:{}}}throw new Error("SITE_EDIT_COMPOSITION_SESSION_REQUIRED: a composition selector is required")}function S(n){return JSON.stringify([n.routeId,n.templateId??null])}function ae(n){return n?JSON.stringify([n.key,n.instanceIndex??null,n.instanceCount??null]):""}function I(n){return JSON.stringify([n.routeId,n.effectiveTemplateId??null])}function F(n){return{routeId:n.routeId,...n.templateId?{effectiveTemplateId:n.templateId}:{}}}function b(n){if(n&&typeof n=="object"){let e=n;if(e.composition&&typeof e.composition=="object"){let t=e.composition;if(typeof t.routeId=="string")return{routeId:t.routeId,...typeof t.templateId=="string"?{templateId:t.templateId}:{}}}}}function ue(n,e,t){let i=g(e==="execute"?b(t.request):t.composition),s={id:n,kind:e,composition:i};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:{...s,...t.mutationContext?{mutationContext:t.mutationContext}:{}}};case"get-object-edit-context":return{type:"request",payload:{...s,key:String(t.key),...t.selectionRef?{selectionRef:t.selectionRef}:{}}};case"get-class-name-source":case"resolve-source-location":return{type:"request",payload:{...s,key:String(t.key)}};case"get-source-file":return{type:"request",payload:{...s,path:String(t.path)}};case"execute":case"get-operation-result":return{type:"request",payload:{...s,request:{...t.request,composition:b(t.request)??i}}}}}export{ee as SITE_EDIT_BRIDGE_CONNECT_TIMEOUT,te as SITE_EDIT_BRIDGE_HEARTBEAT_TIMEOUT,O as SiteEditWebSocketClient,Ie as createSiteEditBridge};
|