@vcp-dev/site-edit-bridge 0.9.6 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { SiteEditCommandSuccess, SiteEditClassNameSourceStyleContext, SiteEditCompositionSelector, SiteEditEvent, SiteEditGetClassNameSourceCommandResult, SiteEditObjectEditContext, SiteEditMutationContext, SiteEditOperationCommandResult, SiteEditOperationRequest, SiteEditRenderDocument, SiteEditResolveSourceLocationInput, SiteEditSourceFileResponse, SiteEditSourceLocation, SiteEditSourceTreeResponse } from "@vcp-dev/contracts";
1
+ import type { SiteEditCommandSuccess, SiteEditClassNameSourceStyleContext, SiteEditCompositionSelector, SiteEditEvent, SiteEditGetClassNameSourceCommandResult, SiteEditObjectEditContext, SiteEditOperationSelectionRef, SiteEditMutationContext, SiteEditOperationCommandResult, SiteEditOperationRequest, SiteEditRenderDocument, SiteEditResolveSourceLocationInput, SiteEditSourceFileResponse, SiteEditSourceLocation, SiteEditSourceTreeResponse } from "@vcp-dev/contracts";
2
2
  import { type SiteEditBridgeInitializeInput, type SiteEditHistoryStatus, type SiteEditBridgeRequestKind } from "./protocol.js";
3
3
  export type { SiteEditHistoryStatus } from "./protocol.js";
4
4
  type SiteEditBridgeCompositionInput = SiteEditCompositionSelector;
@@ -33,7 +33,7 @@ export type SiteEditBridgeClient = {
33
33
  getStyleContext(composition: SiteEditBridgeCompositionInput): Promise<SiteEditCommandSuccess<SiteEditClassNameSourceStyleContext | null>>;
34
34
  ensureDocumentVersion?(composition: SiteEditBridgeCompositionInput, minVersion: number): Promise<SiteEditCommandSuccess<SiteEditRenderDocument>>;
35
35
  acknowledgeDocumentVersion?(composition: SiteEditBridgeCompositionInput, version: number): Promise<SiteEditCommandSuccess<SiteEditRenderDocument>>;
36
- getObjectEditContext(key: string, composition: SiteEditBridgeCompositionInput): Promise<SiteEditCommandSuccess<SiteEditObjectEditContext>>;
36
+ getObjectEditContext(key: string, composition: SiteEditBridgeCompositionInput, selectionRef?: SiteEditOperationSelectionRef): Promise<SiteEditCommandSuccess<SiteEditObjectEditContext>>;
37
37
  getClassNameSource(key: string, composition: SiteEditBridgeCompositionInput): Promise<SiteEditGetClassNameSourceCommandResult>;
38
38
  getSourceTree(composition: SiteEditBridgeCompositionInput): Promise<SiteEditCommandSuccess<SiteEditSourceTreeResponse>>;
39
39
  getSourceFile(input: {
@@ -134,7 +134,7 @@ export declare class SiteEditWebSocketClient implements SiteEditBridgeClient {
134
134
  hash?: string | undefined;
135
135
  }[];
136
136
  } | null>>;
137
- getObjectEditContext(key: string, composition: SiteEditBridgeCompositionInput): Promise<SiteEditCommandSuccess<{
137
+ getObjectEditContext(key: string, composition: SiteEditBridgeCompositionInput, selectionRef?: SiteEditOperationSelectionRef): Promise<SiteEditCommandSuccess<{
138
138
  composition: {
139
139
  routeId: string;
140
140
  effectiveTemplateId?: string | undefined;
@@ -186,7 +186,7 @@ export declare class SiteEditWebSocketClient implements SiteEditBridgeClient {
186
186
  textSegments: {
187
187
  index: number;
188
188
  editable: boolean;
189
- sourceKind: "literal" | "binding" | "imported-binding" | "repeat-template" | null;
189
+ sourceKind: "literal" | "binding" | "repeat-template" | "imported-binding" | null;
190
190
  }[];
191
191
  boundaryKind: "component-boundary" | "repeat-region" | "conditional-region" | "fragment-region" | "opaque-region" | null;
192
192
  sourceLocator?: {
@@ -212,7 +212,7 @@ export declare class SiteEditWebSocketClient implements SiteEditBridgeClient {
212
212
  hasDynamicData: boolean;
213
213
  bindings: {
214
214
  sourceKind: "vcp-cms-collection" | "vcp-cms-form" | "vcp-cms-settings" | "vcp-cms-navigation" | "site-api-route" | "external-api" | "unknown-api";
215
- sourceType: "cms-field" | "api-field";
215
+ sourceType: "api-field" | "cms-field";
216
216
  targetKind: "repeat-region" | "conditional-region" | "text" | "richtext" | "attribute" | "component-prop";
217
217
  targetName: string;
218
218
  confidence: "unknown" | "exact" | "partial" | "safe-derived";
@@ -229,6 +229,60 @@ export declare class SiteEditWebSocketClient implements SiteEditBridgeClient {
229
229
  valuePath?: string | undefined;
230
230
  }[];
231
231
  } | undefined;
232
+ properties?: {
233
+ documentVersion: number;
234
+ items: {
235
+ name: string;
236
+ source: {
237
+ kind: "expression" | "literal" | "binding" | "repeat-template" | "boolean-shorthand";
238
+ raw?: string | undefined;
239
+ };
240
+ resolution: {
241
+ status: "resolved";
242
+ value: import("@vcp-dev/contracts").SiteEditOperationValue;
243
+ } | {
244
+ status: "undefined";
245
+ } | {
246
+ status: "unresolved";
247
+ };
248
+ editMode: "unsupported" | "direct" | "readonly" | "proxy" | "upstream";
249
+ sourceScope: "node" | "repeat-template" | "repeat-item";
250
+ allowedWriteScopes: ("template" | "selection")[];
251
+ diagnostics: {
252
+ code: string;
253
+ message: string;
254
+ }[];
255
+ effectiveWriteTarget?: {
256
+ kind: "jsx-node" | "value-path" | "route-export" | "external-entry";
257
+ isProxy: boolean;
258
+ file?: string | undefined;
259
+ displayPath?: string | undefined;
260
+ sourceType?: "api-field" | "cms-field" | "i18n-message" | "config-entry" | undefined;
261
+ sourceId?: string | undefined;
262
+ } | undefined;
263
+ }[];
264
+ spreads: {
265
+ raw: string;
266
+ sourceRange: {
267
+ start: number;
268
+ end: number;
269
+ };
270
+ order: number;
271
+ diagnostics: {
272
+ code: string;
273
+ message: string;
274
+ }[];
275
+ }[];
276
+ creation: {
277
+ selection: "unsupported" | "direct" | "materialize";
278
+ template: "unsupported" | "direct";
279
+ };
280
+ selectionRef?: {
281
+ key: string;
282
+ instanceIndex?: number | undefined;
283
+ instanceCount?: number | undefined;
284
+ } | undefined;
285
+ } | undefined;
232
286
  }>>;
233
287
  getClassNameSource(key: string, composition: SiteEditBridgeCompositionInput): Promise<SiteEditGetClassNameSourceCommandResult>;
234
288
  getSourceTree(composition: SiteEditBridgeCompositionInput): Promise<SiteEditCommandSuccess<{
package/dist/client.js CHANGED
@@ -1 +1 @@
1
- function T(n){if(!K(n))return n;let e=new Map,t=n.pageComposition.status==="supported"?n.pageComposition.placementUnitKeys:[],o=new Map(n.dynamicDataSummaries??[]),s=i=>{let r=e.get(i);if(r)return r;let a=n.nodes[i];if(!a)throw new Error(`Missing compact document node ${i}`);let[c,u]=a,h=n.tokens[u];if(typeof h!="string")throw new Error(`Missing compact document token ${u}`);let g=`${c===null?"":s(c)}${h}`;return e.set(i,g),g};return{siteId:n.siteId,snapshotId:n.snapshotId,composition:{...n.composition},routeId:n.composition.routeId,version:n.version,pageComposition:n.pageComposition,entries:n.entries.map((i,r)=>{let[a,c,u]=i,h=u===void 0?void 0:t[u];if(u!==void 0&&!h)throw new Error(`Missing page composition unit ${u}`);return{key:s(a),...h?{pageCompositionUnitKey:h}:{},operationSummary:v(c),...o.get(r)?{dynamicDataSummary:o.get(r)}:{}}})}}function v(n){return{canUpdateText:(n&1)!==0,canInsertChild:(n&2)!==0,canMove:(n&4)!==0,canRemove:(n&8)!==0}}function K(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"||!N(e.composition)||typeof e.routeId!="string"||e.routeId!==e.composition.routeId||!Number.isInteger(e.version)||e.version<0||!x(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,i)=>Array.isArray(s)&&s.length===2&&(s[0]===null||f(s[0])&&s[0]<i)&&f(s[1])&&s[1]<e.tokens.length)||!e.entries.every(s=>Array.isArray(s)&&(s.length===2||s.length===3)&&f(s[0])&&s[0]<t.length&&f(s[1])&&s[1]<=15&&(s.length===2||f(s[2]))))return!1;let o=e.dynamicDataSummaries;return o===void 0||Array.isArray(o)&&o.every(s=>Array.isArray(s)&&s.length===2&&f(s[0])&&s[0]<e.entries.length&&x(s[1]))}function x(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function N(n){return!x(n)||typeof n.routeId!="string"?!1:n.effectiveTemplateId===void 0||typeof n.effectiveTemplateId=="string"}function f(n){return typeof n=="number"&&Number.isInteger(n)&&n>=0}var p=class n{constructor(){}static parseMessage(e,t={}){let o=JSON.parse(e);if(!n.isMessage(o,t))throw new Error("Invalid site edit bridge message");return o}static stringifyMessage(e){return JSON.stringify(e)}static extractRequestInfo(e){if(d(e)&&d(e.payload)){let t=typeof e.payload.id=="string"?e.payload.id:"unknown",o=this.isRequestKind(e.payload.kind)?e.payload.kind:"get-document";return{id:t,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,t={}){return!d(e)||typeof e.type!="string"?!1:e.type==="request"?B(e.payload,t):e.type==="response"||e.type==="error"?d(e.payload)&&typeof e.payload.id=="string":e.type==="event"?d(e.payload)&&d(e.payload.event):e.type==="auth"?d(e.payload)&&typeof e.payload.key=="string":e.type==="auth-ok"&&d(e.payload)&&e.payload.ok===!0}};function B(n,e){if(!d(n)||typeof n.id!="string"||!p.isRequestKind(n.kind))return!1;let t=w(n.composition);switch(n.kind){case"initialize-session":return t&&(n.mutationContext===void 0||b(n.mutationContext));case"get-document":case"get-style-context":return t;case"get-object-edit-context":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":return t&&F(n.request)&&(n.request.mutationContext===void 0||b(n.request.mutationContext))&&(e.validateOperationRequest?.(n.request)??!0);case"undo":case"redo":return t&&n.mutationContext===void 0||t&&b(n.mutationContext)}}function F(n){return d(n)&&typeof n.id=="string"&&typeof n.siteId=="string"&&typeof n.baseSnapshotId=="string"&&w(n.composition)&&typeof n.kind=="string"&&d(n.target)&&(n.target.kind!=="route"||w(n.target.composition))&&typeof n.documentVersion=="number"&&Number.isInteger(n.documentVersion)&&n.documentVersion>=0&&d(n.params)}function w(n){return d(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 d(n){return typeof n=="object"&&n!==null}function b(n){return d(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 j="vcp:designer:trace",U="designer_trace",D="__VCP_DESIGNER_TRACE__";var P=/(authorization|cookie|token|secret|providerTrace|headers?|sourceCode|rawSource|fullSource)/i;function W(n=globalThis){let e=n;try{if(e.localStorage?.getItem(j)==="1")return!0}catch{}try{let t=e.location?.search??"";return new URLSearchParams(t).get(U)==="1"}catch{return!1}}function l(n,e={},t=globalThis){if(!W(t))return;let o={type:n,timestamp:Date.now(),payload:$(e)},s=t,i=s[D]??[];i.push(o),i.length>1e3&&i.splice(0,i.length-1e3),s[D]=i;let r=t.console?.debug;o.payload.diagnosticOnly!==!0&&typeof r=="function"&&r.call(t.console,"[designer-trace]",o)}function $(n){return E(n,0)}function E(n,e){if(e>4)return"[truncated]";if(Array.isArray(n))return n.map(o=>E(o,e+1));if(!n||typeof n!="object")return n;let t={};for(let[o,s]of Object.entries(n)){if(P.test(o)){t[o]="[redacted]";continue}t[o]=E(s,e+1)}return t}var R=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===k&&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 o;try{o=this.createSocket(this.options.url)}catch(a){let c=y(a,"WebSocket failed");this.socket=null,this.connectAttempt=null,this.connectPromise=null,this.setConnectionState("failed",c.message),t(c);return}let s={socket:o,settled:!1,reject:t};this.connectAttempt=s,this.socket=o;let i=()=>{this.socket!==o||this.connectAttempt!==s||(s.settled=!0,this.connectAttempt=null,this.connectPromise=null,this.setConnectionState("open"),e())},r=(a,c)=>{this.cleanupSocket(o,a,c)};o.onopen=()=>{if(!(this.socket!==o||this.connectAttempt!==s)){if(this.options.authKey){try{o.send(p.stringifyMessage({type:"auth",payload:{key:this.options.authKey}}))}catch(a){r(y(a,"WebSocket auth failed"),"failed")}return}i()}},o.onerror=a=>{if(this.socket!==o)return;let c=y(a,"WebSocket failed");r(c,"failed")},o.onmessage=a=>{if(this.socket===o){if(this.options.authKey&&this.connectAttempt===s&&!s.settled){this.handleAuthHandshakeMessage(a.data,o,s,()=>{i()});return}this.handleMessage(a.data)}},o.onclose=a=>{if(this.socket!==o)return;let c=this.intentionalClose,u=new Error(J(a,{intentional:c}));r(u,c?"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){let o=this.selector(t);return this.request("get-object-edit-context",{key:e,composition:o})}getClassNameSource(e,t){let o=this.selector(t);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,t){let o=S(e),s={...e,composition:m(o)};return this.request("execute",{request:s})}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 m(e)}request(e,t){let o=this.socket;if(!o||o.readyState!==k||this.connectionState!=="open")return Promise.reject(new Error(`WebSocket is not open (state: ${this.connectionState}, readyState: ${o?.readyState??"none"})`));let s=`${e}-${this.sequence+=1}`,i=H(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:_(t.request,"kind"),documentVersion:_(t.request,"documentVersion")}),new Promise((r,a)=>{let c=this.resolveRequestTimeoutMs(e),u=c>0?setTimeout(()=>{let h=this.pending.get(s);h&&(this.pending.delete(s),l("bridge.response",{id:s,kind:e,ok:!1,timedOut:!0}),h.reject(new Error(`Bridge request timed out after ${c}ms: ${e}`)))},c):null;u?.unref?.(),this.pending.set(s,{kind:e,timeout:u,resolve:h=>r(h),reject:a});try{o.send(p.stringifyMessage(i))}catch(h){let g=y(h,"WebSocket send failed");this.clearPendingRequest(s),a(g),this.cleanupSocket(o,g,"failed")}})}handleAuthHandshakeMessage(e,t,o,s){try{if(p.parseMessage(e).type==="auth-ok"){s();return}throw new Error("Bridge authentication failed")}catch(i){let r=y(i,"Bridge authentication failed");this.connectAttempt===o&&this.cleanupSocket(t,r,"failed")}}handleMessage(e){let t=p.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 o=this.pending.get(t.payload.id);if(o){if(this.clearPendingRequest(t.payload.id),t.type==="error"){l("bridge.response",{id:t.payload.id,kind:o.kind,ok:!1});let s=new Error(t.payload.message);t.payload.code&&(s.code=t.payload.code),o.reject(s);return}l("bridge.response",{id:t.payload.id,kind:o.kind,ok:!0,resultVersion:V(t.payload.result)}),o.resolve(o.kind==="get-document"?{...t.payload.result,data:A(t.payload.result.data,t.payload.result.composition)}:o.kind==="initialize-session"?Q(t.payload.result):t.payload.result)}}rejectAll(e){for(let[t,o]of[...this.pending])this.clearPendingRequest(t),o.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):G[e]??L}cleanupSocket(e,t,o){if(this.socket===e&&(this.socket=null),this.connectAttempt?.socket===e){let s=this.connectAttempt;this.connectAttempt=null,s.settled||(s.settled=!0,s.reject(t))}this.connectPromise=null,this.rejectAll(t),this.setConnectionState(o,t.message),e.onopen=null,e.onmessage=null,e.onerror=null,e.onclose=null;try{(e.readyState===z||e.readyState===k)&&e.close()}catch{}}setConnectionState(e,t){if(this.connectionState===e&&!t)return;this.connectionState=e;let o={state:e,...t?{message:t}:{}};this.options.onConnectionStatus?.(o);for(let s of this.connectionStatusListeners)s(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)}},z=0,k=1,L=15e3,G={"get-source-tree":1e4,"get-source-file":1e4,"resolve-source-location":1e4,execute:6e4,undo:2e4,redo:2e4};function y(n,e){return n instanceof Error?n:new Error(e)}function J(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 _(n,e){if(!n||typeof n!="object")return null;let o=n[e];return typeof o=="string"||typeof o=="number"?o:null}function V(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?m(n.composition):m({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=m(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=!O(e.initialDocument),this.activeCompositionContext=this.sessionInitialized?{...e.initialDocument.composition}:null}async getDocument(e){this.requireBoundComposition(e);let t=O(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 o=await this.params.client.initializeSession({...e,composition:t});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 t=this.requireBoundComposition(e),o=C(t),s=this.styleContextCache.get(o);if(s?.generation===this.styleGeneration)return{ok:!0,data:s.value};let i=this.styleContextInFlight.get(o);if(i?.generation===this.styleGeneration)return i.request;let r=this.styleGeneration,a=this.params.client.getStyleContext(t).then(c=>(this.styleGeneration===r&&this.styleContextCache.set(o,{generation:r,value:c.data}),c)).finally(()=>{this.styleContextInFlight.get(o)?.request===a&&this.styleContextInFlight.delete(o)});return this.styleContextInFlight.set(o,{generation:r,request:a}),a}async ensureDocumentVersion(e,t){this.requireBoundComposition(e);let o=await this.refreshSnapshot(t,"ensure-version");if(o.version<t)throw new Error(`Document refresh returned version ${o.version}, expected at least ${t}`);return{ok:!0,data:o}}async acknowledgeDocumentVersion(e,t){if(this.requireBoundComposition(e),t>this.currentDocument.version){if(this.currentDocument.pageComposition.status==="supported"){let o=await this.refreshSnapshot(t,"ensure-version");if(o.version<t)throw new Error(`Document refresh returned version ${o.version}, expected at least ${t}`);return{ok:!0,data:o}}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){let o=this.requireBoundComposition(t),s=this.objectCacheKey(e,o),i=this.editContextCache.get(s);if(i)return{ok:!0,data:i};let r=this.editContextInFlight.get(s);if(r)return r;let a=this.objectGeneration,c=this.params.client.getObjectEditContext(e,o).then(u=>(this.objectGeneration===a&&this.editContextCache.set(s,u.data),u)).finally(()=>{this.editContextInFlight.get(s)===c&&this.editContextInFlight.delete(s)});return this.editContextInFlight.set(s,c),c}async getClassNameSource(e,t){let o=this.requireBoundComposition(t),s=this.objectCacheKey(e,o),i=this.classNameSourceCache.get(s);if(i)return i;let r=this.classNameSourceInFlight.get(s);if(r)return r;let a=this.objectGeneration,c=this.params.client.getClassNameSource(e,o).then(u=>(this.objectGeneration===a&&this.classNameSourceCache.set(s,u),u)).finally(()=>{this.classNameSourceInFlight.get(s)===c&&this.classNameSourceInFlight.delete(s)});return this.classNameSourceInFlight.set(s,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 o=S(e);o&&this.composition.templateId!==void 0&&this.requireBoundComposition(o);let s={...e,composition:o??this.composition};return this.params.client.execute(s)}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 o=C(this.composition),s=this.refreshInFlight;if(s?.compositionKey===o){l("bridge.document-refresh",{composition:this.composition,routeId:this.composition.routeId,minVersion:e,currentVersion:this.currentDocument.version,deduped:!0,source:t});let r=await s.request;if(typeof e!="number"||r.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 i=this.params.client.getDocument(this.composition).then(r=>(this.currentDocument=r.data,this.activeCompositionContext={...r.data.composition},this.rememberServerConfirmedComposition(r.data.composition),this.observedDocumentVersion=Math.max(this.observedDocumentVersion,r.data.version),this.clearObjectCaches(),this.currentDocument));this.refreshInFlight={compositionKey:o,request:i};try{return await i}finally{this.refreshInFlight?.request===i&&(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){return`${C(t)}\0${e}`}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&&I(t)===I(M(e))}requireBoundComposition(e){let t=e===void 0?this.composition:m(e);if(!this.isAcceptedComposition(t))throw new Error(`Site edit bridge is bound to composition ${JSON.stringify(this.composition)}, received ${JSON.stringify(t)}`);return m(t)}isActiveComposition(e){let t=this.activeCompositionContext??M(this.composition);return I(e)===I(t)}};function O(n){return n.version===0&&n.entries.length===0}function Q(n){let e=n;return{...e,data:{...e.data,document:A(e.data.document,e.composition)}}}function A(n,e){let t=n,o=T(t.routeId?t:{...t,routeId:e?.routeId??t.composition?.routeId});return e?{...o,composition:e}:o}function m(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 I(n){return JSON.stringify([n.routeId,n.effectiveTemplateId??null])}function M(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 H(n,e,t){let o=m(e==="execute"?S(t.request):t.composition),s={id:n,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:{...s,...t.mutationContext?{mutationContext:t.mutationContext}:{}}};case"get-object-edit-context":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":return{type:"request",payload:{...s,request:{...t.request,composition:S(t.request)??o}}}}}export{R as SiteEditWebSocketClient,ie as createSiteEditBridge};
1
+ function T(n){if(!N(n))return n;let e=new Map,t=n.pageComposition.status==="supported"?n.pageComposition.placementUnitKeys:[],o=new Map(n.dynamicDataSummaries??[]),s=i=>{let r=e.get(i);if(r)return r;let c=n.nodes[i];if(!c)throw new Error(`Missing compact document node ${i}`);let[a,u]=c,d=n.tokens[u];if(typeof d!="string")throw new Error(`Missing compact document token ${u}`);let g=`${a===null?"":s(a)}${d}`;return e.set(i,g),g};return{siteId:n.siteId,snapshotId:n.snapshotId,composition:{...n.composition},routeId:n.composition.routeId,version:n.version,pageComposition:n.pageComposition,entries:n.entries.map((i,r)=>{let[c,a,u]=i,d=u===void 0?void 0:t[u];if(u!==void 0&&!d)throw new Error(`Missing page composition unit ${u}`);return{key:s(c),...d?{pageCompositionUnitKey:d}:{},operationSummary:v(a),...o.get(r)?{dynamicDataSummary:o.get(r)}:{}}})}}function v(n){return{canUpdateText:(n&1)!==0,canInsertChild:(n&2)!==0,canMove:(n&4)!==0,canRemove:(n&8)!==0}}function N(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"||!K(e.composition)||typeof e.routeId!="string"||e.routeId!==e.composition.routeId||!Number.isInteger(e.version)||e.version<0||!x(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,i)=>Array.isArray(s)&&s.length===2&&(s[0]===null||f(s[0])&&s[0]<i)&&f(s[1])&&s[1]<e.tokens.length)||!e.entries.every(s=>Array.isArray(s)&&(s.length===2||s.length===3)&&f(s[0])&&s[0]<t.length&&f(s[1])&&s[1]<=15&&(s.length===2||f(s[2]))))return!1;let o=e.dynamicDataSummaries;return o===void 0||Array.isArray(o)&&o.every(s=>Array.isArray(s)&&s.length===2&&f(s[0])&&s[0]<e.entries.length&&x(s[1]))}function x(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function K(n){return!x(n)||typeof n.routeId!="string"?!1:n.effectiveTemplateId===void 0||typeof n.effectiveTemplateId=="string"}function f(n){return typeof n=="number"&&Number.isInteger(n)&&n>=0}var p=class n{constructor(){}static parseMessage(e,t={}){let o=JSON.parse(e);if(!n.isMessage(o,t))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 t=typeof e.payload.id=="string"?e.payload.id:"unknown",o=this.isRequestKind(e.payload.kind)?e.payload.kind:"get-document";return{id:t,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,t={}){return!h(e)||typeof e.type!="string"?!1:e.type==="request"?B(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==="auth-ok"&&h(e.payload)&&e.payload.ok===!0}};function B(n,e){if(!h(n)||typeof n.id!="string"||!p.isRequestKind(n.kind))return!1;let t=w(n.composition);switch(n.kind){case"initialize-session":return t&&(n.mutationContext===void 0||b(n.mutationContext));case"get-document":case"get-style-context":return t;case"get-object-edit-context":return typeof n.key=="string"&&t&&j(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":return t&&F(n.request)&&(n.request.mutationContext===void 0||b(n.request.mutationContext))&&(e.validateOperationRequest?.(n.request)??!0);case"undo":case"redo":return t&&n.mutationContext===void 0||t&&b(n.mutationContext)}}function j(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(o=>o==="key"||o==="instanceIndex"||o==="instanceCount")}function F(n){return h(n)&&typeof n.id=="string"&&typeof n.siteId=="string"&&typeof n.baseSnapshotId=="string"&&w(n.composition)&&typeof n.kind=="string"&&h(n.target)&&(n.target.kind!=="route"||w(n.target.composition))&&typeof n.documentVersion=="number"&&Number.isInteger(n.documentVersion)&&n.documentVersion>=0&&h(n.params)}function w(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 b(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 U="vcp:designer:trace",P="designer_trace",R="__VCP_DESIGNER_TRACE__";var W=/(authorization|cookie|token|secret|providerTrace|headers?|sourceCode|rawSource|fullSource)/i;function $(n=globalThis){let e=n;try{if(e.localStorage?.getItem(U)==="1")return!0}catch{}try{let t=e.location?.search??"";return new URLSearchParams(t).get(P)==="1"}catch{return!1}}function l(n,e={},t=globalThis){if(!$(t))return;let o={type:n,timestamp:Date.now(),payload:z(e)},s=t,i=s[R]??[];i.push(o),i.length>1e3&&i.splice(0,i.length-1e3),s[R]=i;let r=t.console?.debug;o.payload.diagnosticOnly!==!0&&typeof r=="function"&&r.call(t.console,"[designer-trace]",o)}function z(n){return E(n,0)}function E(n,e){if(e>4)return"[truncated]";if(Array.isArray(n))return n.map(o=>E(o,e+1));if(!n||typeof n!="object")return n;let t={};for(let[o,s]of Object.entries(n)){if(W.test(o)){t[o]="[redacted]";continue}t[o]=E(s,e+1)}return t}var D=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===k&&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 o;try{o=this.createSocket(this.options.url)}catch(c){let a=y(c,"WebSocket failed");this.socket=null,this.connectAttempt=null,this.connectPromise=null,this.setConnectionState("failed",a.message),t(a);return}let s={socket:o,settled:!1,reject:t};this.connectAttempt=s,this.socket=o;let i=()=>{this.socket!==o||this.connectAttempt!==s||(s.settled=!0,this.connectAttempt=null,this.connectPromise=null,this.setConnectionState("open"),e())},r=(c,a)=>{this.cleanupSocket(o,c,a)};o.onopen=()=>{if(!(this.socket!==o||this.connectAttempt!==s)){if(this.options.authKey){try{o.send(p.stringifyMessage({type:"auth",payload:{key:this.options.authKey}}))}catch(c){r(y(c,"WebSocket auth failed"),"failed")}return}i()}},o.onerror=c=>{if(this.socket!==o)return;let a=y(c,"WebSocket failed");r(a,"failed")},o.onmessage=c=>{if(this.socket===o){if(this.options.authKey&&this.connectAttempt===s&&!s.settled){this.handleAuthHandshakeMessage(c.data,o,s,()=>{i()});return}this.handleMessage(c.data)}},o.onclose=c=>{if(this.socket!==o)return;let a=this.intentionalClose,u=new Error(V(c,{intentional:a}));r(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 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,o){let s=this.selector(t);return this.request("get-object-edit-context",{key:e,composition:s,...o?{selectionRef:o}:{}})}getClassNameSource(e,t){let o=this.selector(t);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,t){let o=S(e),s={...e,composition:m(o)};return this.request("execute",{request:s})}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 m(e)}request(e,t){let o=this.socket;if(!o||o.readyState!==k||this.connectionState!=="open")return Promise.reject(new Error(`WebSocket is not open (state: ${this.connectionState}, readyState: ${o?.readyState??"none"})`));let s=`${e}-${this.sequence+=1}`,i=Z(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:_(t.request,"kind"),documentVersion:_(t.request,"documentVersion")}),new Promise((r,c)=>{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=>r(d),reject:c});try{o.send(p.stringifyMessage(i))}catch(d){let g=y(d,"WebSocket send failed");this.clearPendingRequest(s),c(g),this.cleanupSocket(o,g,"failed")}})}handleAuthHandshakeMessage(e,t,o,s){try{if(p.parseMessage(e).type==="auth-ok"){s();return}throw new Error("Bridge authentication failed")}catch(i){let r=y(i,"Bridge authentication failed");this.connectAttempt===o&&this.cleanupSocket(t,r,"failed")}}handleMessage(e){let t=p.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 o=this.pending.get(t.payload.id);if(o){if(this.clearPendingRequest(t.payload.id),t.type==="error"){l("bridge.response",{id:t.payload.id,kind:o.kind,ok:!1});let s=new Error(t.payload.message);t.payload.code&&(s.code=t.payload.code),o.reject(s);return}l("bridge.response",{id:t.payload.id,kind:o.kind,ok:!0,resultVersion:Q(t.payload.result)}),o.resolve(o.kind==="get-document"?{...t.payload.result,data:A(t.payload.result.data,t.payload.result.composition)}:o.kind==="initialize-session"?H(t.payload.result):t.payload.result)}}rejectAll(e){for(let[t,o]of[...this.pending])this.clearPendingRequest(t),o.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):G[e]??J}cleanupSocket(e,t,o){if(this.socket===e&&(this.socket=null),this.connectAttempt?.socket===e){let s=this.connectAttempt;this.connectAttempt=null,s.settled||(s.settled=!0,s.reject(t))}this.connectPromise=null,this.rejectAll(t),this.setConnectionState(o,t.message),e.onopen=null,e.onmessage=null,e.onerror=null,e.onclose=null;try{(e.readyState===L||e.readyState===k)&&e.close()}catch{}}setConnectionState(e,t){if(this.connectionState===e&&!t)return;this.connectionState=e;let o={state:e,...t?{message:t}:{}};this.options.onConnectionStatus?.(o);for(let s of this.connectionStatusListeners)s(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)}},L=0,k=1,J=15e3,G={"get-source-tree":1e4,"get-source-file":1e4,"resolve-source-location":1e4,execute:6e4,undo:2e4,redo:2e4};function y(n,e){return n instanceof Error?n:new Error(e)}function V(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 _(n,e){if(!n||typeof n!="object")return null;let o=n[e];return typeof o=="string"||typeof o=="number"?o:null}function Q(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 ce(n){let e="composition"in n?m(n.composition):m({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=m(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=!O(e.initialDocument),this.activeCompositionContext=this.sessionInitialized?{...e.initialDocument.composition}:null}async getDocument(e){this.requireBoundComposition(e);let t=O(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 o=await this.params.client.initializeSession({...e,composition:t});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 t=this.requireBoundComposition(e),o=C(t),s=this.styleContextCache.get(o);if(s?.generation===this.styleGeneration)return{ok:!0,data:s.value};let i=this.styleContextInFlight.get(o);if(i?.generation===this.styleGeneration)return i.request;let r=this.styleGeneration,c=this.params.client.getStyleContext(t).then(a=>(this.styleGeneration===r&&this.styleContextCache.set(o,{generation:r,value:a.data}),a)).finally(()=>{this.styleContextInFlight.get(o)?.request===c&&this.styleContextInFlight.delete(o)});return this.styleContextInFlight.set(o,{generation:r,request:c}),c}async ensureDocumentVersion(e,t){this.requireBoundComposition(e);let o=await this.refreshSnapshot(t,"ensure-version");if(o.version<t)throw new Error(`Document refresh returned version ${o.version}, expected at least ${t}`);return{ok:!0,data:o}}async acknowledgeDocumentVersion(e,t){if(this.requireBoundComposition(e),t>this.currentDocument.version){if(this.currentDocument.pageComposition.status==="supported"){let o=await this.refreshSnapshot(t,"ensure-version");if(o.version<t)throw new Error(`Document refresh returned version ${o.version}, expected at least ${t}`);return{ok:!0,data:o}}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,o){let s=this.requireBoundComposition(t),i=this.objectCacheKey(e,s,o),r=this.editContextCache.get(i);if(r)return{ok:!0,data:r};let c=this.editContextInFlight.get(i);if(c)return c;let a=this.objectGeneration,u=this.params.client.getObjectEditContext(e,s,...o?[o]:[]).then(d=>(this.objectGeneration===a&&this.editContextCache.set(i,d.data),d)).finally(()=>{this.editContextInFlight.get(i)===u&&this.editContextInFlight.delete(i)});return this.editContextInFlight.set(i,u),u}async getClassNameSource(e,t){let o=this.requireBoundComposition(t),s=this.objectCacheKey(e,o),i=this.classNameSourceCache.get(s);if(i)return i;let r=this.classNameSourceInFlight.get(s);if(r)return r;let c=this.objectGeneration,a=this.params.client.getClassNameSource(e,o).then(u=>(this.objectGeneration===c&&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 o=S(e);o&&this.composition.templateId!==void 0&&this.requireBoundComposition(o);let s={...e,composition:o??this.composition};return this.params.client.execute(s)}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 o=C(this.composition),s=this.refreshInFlight;if(s?.compositionKey===o){l("bridge.document-refresh",{composition:this.composition,routeId:this.composition.routeId,minVersion:e,currentVersion:this.currentDocument.version,deduped:!0,source:t});let r=await s.request;if(typeof e!="number"||r.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 i=this.params.client.getDocument(this.composition).then(r=>(this.currentDocument=r.data,this.activeCompositionContext={...r.data.composition},this.rememberServerConfirmedComposition(r.data.composition),this.observedDocumentVersion=Math.max(this.observedDocumentVersion,r.data.version),this.clearObjectCaches(),this.currentDocument));this.refreshInFlight={compositionKey:o,request:i};try{return await i}finally{this.refreshInFlight?.request===i&&(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,o){return`${C(t)}\0${e}\0${Y(o)}`}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&&I(t)===I(M(e))}requireBoundComposition(e){let t=e===void 0?this.composition:m(e);if(!this.isAcceptedComposition(t))throw new Error(`Site edit bridge is bound to composition ${JSON.stringify(this.composition)}, received ${JSON.stringify(t)}`);return m(t)}isActiveComposition(e){let t=this.activeCompositionContext??M(this.composition);return I(e)===I(t)}};function O(n){return n.version===0&&n.entries.length===0}function H(n){let e=n;return{...e,data:{...e.data,document:A(e.data.document,e.composition)}}}function A(n,e){let t=n,o=T(t.routeId?t:{...t,routeId:e?.routeId??t.composition?.routeId});return e?{...o,composition:e}:o}function m(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 Y(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 M(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 Z(n,e,t){let o=m(e==="execute"?S(t.request):t.composition),s={id:n,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:{...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":return{type:"request",payload:{...s,request:{...t.request,composition:S(t.request)??o}}}}}export{D as SiteEditWebSocketClient,ce as createSiteEditBridge};