@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/auto-bootstrap.js +4 -4
- package/dist/client.d.ts +59 -5
- package/dist/client.js +1 -1
- package/dist/index.js +13 -13
- package/dist/next-dev-server.js +3 -3
- package/dist/property-preview.d.ts +26 -0
- package/dist/protocol.d.ts +8 -3
- package/dist/protocol.js +29 -1
- package/dist/server.js +2 -2
- package/dist/window-message.d.ts +12 -1
- package/dist/window-message.js +1 -1
- package/package.json +3 -3
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" | "
|
|
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: "
|
|
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};
|