@vcp-dev/site-edit-bridge 0.6.10 → 0.7.0
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/README.md +27 -8
- package/dist/auto-bootstrap.d.ts +19 -2
- package/dist/auto-bootstrap.js +11 -11
- package/dist/client.d.ts +76 -36
- package/dist/client.js +1 -1
- package/dist/document-codec.d.ts +2 -0
- package/dist/document-codec.js +1 -1
- package/dist/index.js +8 -8
- package/dist/next-dev-server.js +3 -3
- package/dist/protocol.d.ts +71 -143
- package/dist/protocol.js +281 -182
- package/dist/server.d.ts +7 -5
- package/dist/server.js +2 -2
- package/dist/window-message.d.ts +26 -12
- package/dist/window-message.js +1 -1
- package/package.json +3 -3
package/dist/client.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { SiteEditCommandSuccess, SiteEditClassNameSourceStyleContext, SiteEditEvent, SiteEditGetClassNameSourceCommandResult, SiteEditObjectEditContext, SiteEditMutationContext,
|
|
2
|
-
import { type SiteEditHistoryStatus, type SiteEditBridgeRequestKind } from "./protocol.js";
|
|
1
|
+
import type { SiteEditCommandSuccess, SiteEditClassNameSourceStyleContext, SiteEditCompositionSelector, SiteEditEvent, SiteEditGetClassNameSourceCommandResult, SiteEditObjectEditContext, SiteEditMutationContext, SiteEditOperationCommandResult, SiteEditOperationRequest, SiteEditRenderDocument, SiteEditResolveSourceLocationInput, SiteEditSourceFileResponse, SiteEditSourceLocation, SiteEditSourceTreeResponse } from "@vcp-dev/contracts";
|
|
2
|
+
import { type SiteEditBridgeInitializeInput, type SiteEditHistoryStatus, type SiteEditBridgeRequestKind } from "./protocol.js";
|
|
3
3
|
export type { SiteEditHistoryStatus } from "./protocol.js";
|
|
4
|
+
type SiteEditBridgeCompositionInput = SiteEditCompositionSelector;
|
|
4
5
|
export type SiteEditBrowserSocketLike = {
|
|
5
6
|
readonly readyState: number;
|
|
6
7
|
onopen: (() => void) | null;
|
|
@@ -23,25 +24,26 @@ export type SiteEditBridgeConnectionStatus = {
|
|
|
23
24
|
message?: string;
|
|
24
25
|
};
|
|
25
26
|
export type SiteEditBridgeClient = {
|
|
26
|
-
initializeSession?(input:
|
|
27
|
+
initializeSession?(input: SiteEditBridgeInitializeInput): Promise<SiteEditCommandSuccess<{
|
|
27
28
|
document: SiteEditRenderDocument;
|
|
28
29
|
historyStatus: SiteEditHistoryStatus;
|
|
29
30
|
}>>;
|
|
30
|
-
getDocument(
|
|
31
|
-
getHistoryStatus(): Promise<SiteEditCommandSuccess<SiteEditHistoryStatus>>;
|
|
32
|
-
getStyleContext(
|
|
33
|
-
ensureDocumentVersion?(
|
|
34
|
-
acknowledgeDocumentVersion?(
|
|
35
|
-
getObjectEditContext(key: string,
|
|
36
|
-
getClassNameSource(key: string,
|
|
37
|
-
getSourceTree(): Promise<SiteEditCommandSuccess<SiteEditSourceTreeResponse>>;
|
|
31
|
+
getDocument(composition: SiteEditBridgeCompositionInput): Promise<SiteEditCommandSuccess<SiteEditRenderDocument>>;
|
|
32
|
+
getHistoryStatus(composition: SiteEditBridgeCompositionInput): Promise<SiteEditCommandSuccess<SiteEditHistoryStatus>>;
|
|
33
|
+
getStyleContext(composition: SiteEditBridgeCompositionInput): Promise<SiteEditCommandSuccess<SiteEditClassNameSourceStyleContext | null>>;
|
|
34
|
+
ensureDocumentVersion?(composition: SiteEditBridgeCompositionInput, minVersion: number): Promise<SiteEditCommandSuccess<SiteEditRenderDocument>>;
|
|
35
|
+
acknowledgeDocumentVersion?(composition: SiteEditBridgeCompositionInput, version: number): Promise<SiteEditCommandSuccess<SiteEditRenderDocument>>;
|
|
36
|
+
getObjectEditContext(key: string, composition: SiteEditBridgeCompositionInput): Promise<SiteEditCommandSuccess<SiteEditObjectEditContext>>;
|
|
37
|
+
getClassNameSource(key: string, composition: SiteEditBridgeCompositionInput): Promise<SiteEditGetClassNameSourceCommandResult>;
|
|
38
|
+
getSourceTree(composition: SiteEditBridgeCompositionInput): Promise<SiteEditCommandSuccess<SiteEditSourceTreeResponse>>;
|
|
38
39
|
getSourceFile(input: {
|
|
39
40
|
path: string;
|
|
41
|
+
composition: SiteEditBridgeCompositionInput;
|
|
40
42
|
}): Promise<SiteEditCommandSuccess<SiteEditSourceFileResponse>>;
|
|
41
43
|
resolveSourceLocation(input: SiteEditResolveSourceLocationInput): Promise<SiteEditCommandSuccess<SiteEditSourceLocation>>;
|
|
42
|
-
execute(request: SiteEditOperationRequest, mutationContext?: SiteEditMutationContext): Promise<SiteEditOperationCommandResult>;
|
|
43
|
-
undo(mutationContext?: SiteEditMutationContext): Promise<SiteEditOperationCommandResult>;
|
|
44
|
-
redo(mutationContext?: SiteEditMutationContext): Promise<SiteEditOperationCommandResult>;
|
|
44
|
+
execute(request: SiteEditOperationRequest | Record<string, unknown>, mutationContext?: SiteEditMutationContext): Promise<SiteEditOperationCommandResult>;
|
|
45
|
+
undo(composition: SiteEditBridgeCompositionInput, mutationContext?: SiteEditMutationContext): Promise<SiteEditOperationCommandResult>;
|
|
46
|
+
redo(composition: SiteEditBridgeCompositionInput, mutationContext?: SiteEditMutationContext): Promise<SiteEditOperationCommandResult>;
|
|
45
47
|
subscribe(listener: (event: SiteEditEvent) => void): () => void;
|
|
46
48
|
};
|
|
47
49
|
export declare class SiteEditWebSocketClient implements SiteEditBridgeClient {
|
|
@@ -66,10 +68,13 @@ export declare class SiteEditWebSocketClient implements SiteEditBridgeClient {
|
|
|
66
68
|
disconnect(): void;
|
|
67
69
|
getConnectionState(): SiteEditBridgeConnectionState;
|
|
68
70
|
subscribeConnectionStatus(listener: (status: SiteEditBridgeConnectionStatus) => void): () => void;
|
|
69
|
-
getDocument(
|
|
71
|
+
getDocument(composition: SiteEditBridgeCompositionInput): Promise<SiteEditCommandSuccess<{
|
|
70
72
|
siteId: string;
|
|
71
73
|
snapshotId: string;
|
|
72
|
-
|
|
74
|
+
composition: {
|
|
75
|
+
routeId: string;
|
|
76
|
+
effectiveTemplateId?: string | undefined;
|
|
77
|
+
};
|
|
73
78
|
version: number;
|
|
74
79
|
entries: {
|
|
75
80
|
key: string;
|
|
@@ -107,12 +112,16 @@ export declare class SiteEditWebSocketClient implements SiteEditBridgeClient {
|
|
|
107
112
|
}[];
|
|
108
113
|
};
|
|
109
114
|
}>>;
|
|
110
|
-
initializeSession(input:
|
|
115
|
+
initializeSession(input: SiteEditBridgeInitializeInput): Promise<SiteEditCommandSuccess<{
|
|
111
116
|
document: SiteEditRenderDocument;
|
|
112
117
|
historyStatus: SiteEditHistoryStatus;
|
|
113
118
|
}>>;
|
|
114
|
-
getHistoryStatus(): Promise<SiteEditCommandSuccess<SiteEditHistoryStatus>>;
|
|
115
|
-
getStyleContext(
|
|
119
|
+
getHistoryStatus(composition: SiteEditBridgeCompositionInput): Promise<SiteEditCommandSuccess<SiteEditHistoryStatus>>;
|
|
120
|
+
getStyleContext(composition: SiteEditBridgeCompositionInput): Promise<SiteEditCommandSuccess<{
|
|
121
|
+
composition: {
|
|
122
|
+
routeId: string;
|
|
123
|
+
effectiveTemplateId?: string | undefined;
|
|
124
|
+
};
|
|
116
125
|
revision: string;
|
|
117
126
|
entryCss: {
|
|
118
127
|
path: string;
|
|
@@ -125,7 +134,11 @@ export declare class SiteEditWebSocketClient implements SiteEditBridgeClient {
|
|
|
125
134
|
hash?: string | undefined;
|
|
126
135
|
}[];
|
|
127
136
|
} | null>>;
|
|
128
|
-
getObjectEditContext(key: string,
|
|
137
|
+
getObjectEditContext(key: string, composition: SiteEditBridgeCompositionInput): Promise<SiteEditCommandSuccess<{
|
|
138
|
+
composition: {
|
|
139
|
+
routeId: string;
|
|
140
|
+
effectiveTemplateId?: string | undefined;
|
|
141
|
+
};
|
|
129
142
|
key: string;
|
|
130
143
|
tag: string;
|
|
131
144
|
label: string;
|
|
@@ -138,6 +151,10 @@ export declare class SiteEditWebSocketClient implements SiteEditBridgeClient {
|
|
|
138
151
|
componentName: string;
|
|
139
152
|
sourceFile: string;
|
|
140
153
|
capabilities: {
|
|
154
|
+
composition: {
|
|
155
|
+
routeId: string;
|
|
156
|
+
effectiveTemplateId?: string | undefined;
|
|
157
|
+
};
|
|
141
158
|
key: string;
|
|
142
159
|
canUpdateText: boolean;
|
|
143
160
|
canInsertChild: boolean;
|
|
@@ -149,19 +166,19 @@ export declare class SiteEditWebSocketClient implements SiteEditBridgeClient {
|
|
|
149
166
|
}[];
|
|
150
167
|
editModes?: {
|
|
151
168
|
updateText?: {
|
|
152
|
-
mode: "unsupported" | "
|
|
169
|
+
mode: "unsupported" | "direct" | "readonly" | "proxy" | "upstream";
|
|
153
170
|
reasonCode?: string | undefined;
|
|
154
171
|
} | undefined;
|
|
155
172
|
insertChild?: {
|
|
156
|
-
mode: "unsupported" | "
|
|
173
|
+
mode: "unsupported" | "direct" | "readonly" | "proxy" | "upstream";
|
|
157
174
|
reasonCode?: string | undefined;
|
|
158
175
|
} | undefined;
|
|
159
176
|
move?: {
|
|
160
|
-
mode: "unsupported" | "
|
|
177
|
+
mode: "unsupported" | "direct" | "readonly" | "proxy" | "upstream";
|
|
161
178
|
reasonCode?: string | undefined;
|
|
162
179
|
} | undefined;
|
|
163
180
|
remove?: {
|
|
164
|
-
mode: "unsupported" | "
|
|
181
|
+
mode: "unsupported" | "direct" | "readonly" | "proxy" | "upstream";
|
|
165
182
|
reasonCode?: string | undefined;
|
|
166
183
|
} | undefined;
|
|
167
184
|
} | undefined;
|
|
@@ -185,7 +202,7 @@ export declare class SiteEditWebSocketClient implements SiteEditBridgeClient {
|
|
|
185
202
|
textPreview?: string | undefined;
|
|
186
203
|
} | undefined;
|
|
187
204
|
provenanceChain?: {
|
|
188
|
-
editMode: "unsupported" | "
|
|
205
|
+
editMode: "unsupported" | "direct" | "readonly" | "proxy" | "upstream";
|
|
189
206
|
diagnostics: {
|
|
190
207
|
code: string;
|
|
191
208
|
message: string;
|
|
@@ -196,9 +213,9 @@ export declare class SiteEditWebSocketClient implements SiteEditBridgeClient {
|
|
|
196
213
|
bindings: {
|
|
197
214
|
sourceKind: "vcp-cms-collection" | "vcp-cms-form" | "vcp-cms-settings" | "vcp-cms-navigation" | "site-api-route" | "external-api" | "unknown-api";
|
|
198
215
|
sourceType: "cms-field" | "api-field";
|
|
199
|
-
targetKind: "
|
|
216
|
+
targetKind: "repeat-region" | "text" | "richtext" | "attribute" | "component-prop";
|
|
200
217
|
targetName: string;
|
|
201
|
-
confidence: "unknown" | "exact" | "
|
|
218
|
+
confidence: "unknown" | "exact" | "partial" | "safe-derived";
|
|
202
219
|
readonly: true;
|
|
203
220
|
evidence: {
|
|
204
221
|
file: string;
|
|
@@ -213,8 +230,12 @@ export declare class SiteEditWebSocketClient implements SiteEditBridgeClient {
|
|
|
213
230
|
}[];
|
|
214
231
|
} | undefined;
|
|
215
232
|
}>>;
|
|
216
|
-
getClassNameSource(key: string,
|
|
217
|
-
getSourceTree(): Promise<SiteEditCommandSuccess<{
|
|
233
|
+
getClassNameSource(key: string, composition: SiteEditBridgeCompositionInput): Promise<SiteEditGetClassNameSourceCommandResult>;
|
|
234
|
+
getSourceTree(composition: SiteEditBridgeCompositionInput): Promise<SiteEditCommandSuccess<{
|
|
235
|
+
composition: {
|
|
236
|
+
routeId: string;
|
|
237
|
+
effectiveTemplateId?: string | undefined;
|
|
238
|
+
};
|
|
218
239
|
nodes: import("@vcp-dev/contracts").SiteEditSourceTreeNode[];
|
|
219
240
|
totalFiles: number;
|
|
220
241
|
defaultPath?: string | undefined;
|
|
@@ -227,7 +248,12 @@ export declare class SiteEditWebSocketClient implements SiteEditBridgeClient {
|
|
|
227
248
|
}>>;
|
|
228
249
|
getSourceFile(input: {
|
|
229
250
|
path: string;
|
|
251
|
+
composition: SiteEditBridgeCompositionInput;
|
|
230
252
|
}): Promise<SiteEditCommandSuccess<{
|
|
253
|
+
composition: {
|
|
254
|
+
routeId: string;
|
|
255
|
+
effectiveTemplateId?: string | undefined;
|
|
256
|
+
};
|
|
231
257
|
path: string;
|
|
232
258
|
sizeBytes: number;
|
|
233
259
|
kind: "text";
|
|
@@ -236,6 +262,10 @@ export declare class SiteEditWebSocketClient implements SiteEditBridgeClient {
|
|
|
236
262
|
content: string;
|
|
237
263
|
contentHash?: string | undefined;
|
|
238
264
|
} | {
|
|
265
|
+
composition: {
|
|
266
|
+
routeId: string;
|
|
267
|
+
effectiveTemplateId?: string | undefined;
|
|
268
|
+
};
|
|
239
269
|
path: string;
|
|
240
270
|
sizeBytes: number;
|
|
241
271
|
kind: "binary";
|
|
@@ -248,6 +278,10 @@ export declare class SiteEditWebSocketClient implements SiteEditBridgeClient {
|
|
|
248
278
|
}>>;
|
|
249
279
|
resolveSourceLocation(input: SiteEditResolveSourceLocationInput): Promise<SiteEditCommandSuccess<{
|
|
250
280
|
key: string;
|
|
281
|
+
composition: {
|
|
282
|
+
routeId: string;
|
|
283
|
+
effectiveTemplateId?: string | undefined;
|
|
284
|
+
};
|
|
251
285
|
sourceFile: string;
|
|
252
286
|
componentName: string;
|
|
253
287
|
openingElementRange: {
|
|
@@ -257,13 +291,13 @@ export declare class SiteEditWebSocketClient implements SiteEditBridgeClient {
|
|
|
257
291
|
endColumn: number;
|
|
258
292
|
};
|
|
259
293
|
structuralPath: string;
|
|
260
|
-
routeId?: string | undefined;
|
|
261
294
|
textPreview?: string | undefined;
|
|
262
295
|
}>>;
|
|
263
|
-
execute(request: SiteEditOperationRequest, _mutationContext?: SiteEditMutationContext): Promise<SiteEditOperationCommandResult>;
|
|
264
|
-
undo(_mutationContext?: SiteEditMutationContext): Promise<SiteEditOperationCommandResult>;
|
|
265
|
-
redo(_mutationContext?: SiteEditMutationContext): Promise<SiteEditOperationCommandResult>;
|
|
296
|
+
execute(request: SiteEditOperationRequest | Record<string, unknown>, _mutationContext?: SiteEditMutationContext): Promise<SiteEditOperationCommandResult>;
|
|
297
|
+
undo(composition: SiteEditBridgeCompositionInput, _mutationContext?: SiteEditMutationContext): Promise<SiteEditOperationCommandResult>;
|
|
298
|
+
redo(composition: SiteEditBridgeCompositionInput, _mutationContext?: SiteEditMutationContext): Promise<SiteEditOperationCommandResult>;
|
|
266
299
|
subscribe(listener: (event: SiteEditEvent) => void): () => void;
|
|
300
|
+
private selector;
|
|
267
301
|
private request;
|
|
268
302
|
private handleAuthHandshakeMessage;
|
|
269
303
|
private handleMessage;
|
|
@@ -276,13 +310,19 @@ export declare class SiteEditWebSocketClient implements SiteEditBridgeClient {
|
|
|
276
310
|
private createSocket;
|
|
277
311
|
}
|
|
278
312
|
export type SiteEditBridge = SiteEditBridgeClient & {
|
|
279
|
-
initializeSession(input:
|
|
313
|
+
initializeSession(input: SiteEditBridgeInitializeInput): Promise<SiteEditCommandSuccess<{
|
|
280
314
|
document: SiteEditRenderDocument;
|
|
281
315
|
historyStatus: SiteEditHistoryStatus;
|
|
282
316
|
}>>;
|
|
283
317
|
};
|
|
284
|
-
|
|
318
|
+
type SiteEditBridgeCreateParams = {
|
|
319
|
+
composition: SiteEditCompositionSelector;
|
|
320
|
+
initialDocument: SiteEditRenderDocument;
|
|
321
|
+
client: SiteEditBridgeClient;
|
|
322
|
+
} | {
|
|
323
|
+
/** Compatibility form for callers that intentionally select no template. */
|
|
285
324
|
routeId: string;
|
|
286
325
|
initialDocument: SiteEditRenderDocument;
|
|
287
326
|
client: SiteEditBridgeClient;
|
|
288
|
-
}
|
|
327
|
+
};
|
|
328
|
+
export declare function createSiteEditBridge(params: SiteEditBridgeCreateParams): SiteEditBridge;
|
package/dist/client.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function y(n){if(!M(n))return n;let e=new Map,t=n.pageComposition.status==="supported"?n.pageComposition.placementUnitKeys:[],s=new Map(n.dynamicDataSummaries??[]),r=o=>{let a=e.get(o);if(a)return a;let i=n.nodes[o];if(!i)throw new Error(`Missing compact document node ${o}`);let[c,d]=i,u=n.tokens[d];if(typeof u!="string")throw new Error(`Missing compact document token ${d}`);let f=`${c===null?"":r(c)}${u}`;return e.set(o,f),f};return{siteId:n.siteId,snapshotId:n.snapshotId,routeId:n.routeId,version:n.version,pageComposition:n.pageComposition,entries:n.entries.map((o,a)=>{let[i,c,d]=o,u=d===void 0?void 0:t[d];if(d!==void 0&&!u)throw new Error(`Missing page composition unit ${d}`);return{key:r(i),...u?{pageCompositionUnitKey:u}:{},operationSummary:D(c),...s.get(a)?{dynamicDataSummary:s.get(a)}:{}}})}}function D(n){return{canUpdateText:(n&1)!==0,canInsertChild:(n&2)!==0,canMove:(n&4)!==0,canRemove:(n&8)!==0}}function M(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"||typeof e.routeId!="string"||!Number.isInteger(e.version)||e.version<0||!x(e.pageComposition)||!Array.isArray(e.tokens)||!e.tokens.every(r=>typeof r=="string")||!Array.isArray(e.nodes)||!Array.isArray(e.entries))return!1;let t=e.nodes;if(!t.every((r,o)=>Array.isArray(r)&&r.length===2&&(r[0]===null||g(r[0])&&r[0]<o)&&g(r[1])&&r[1]<e.tokens.length)||!e.entries.every(r=>Array.isArray(r)&&(r.length===2||r.length===3)&&g(r[0])&&r[0]<t.length&&g(r[1])&&r[1]<=15&&(r.length===2||g(r[2]))))return!1;let s=e.dynamicDataSummaries;return s===void 0||Array.isArray(s)&&s.every(r=>Array.isArray(r)&&r.length===2&&g(r[0])&&r[0]<e.entries.length&&x(r[1]))}function x(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function g(n){return typeof n=="number"&&Number.isInteger(n)&&n>=0}var p=class n{constructor(){}static parseMessage(e,t={}){let s=JSON.parse(e);if(!n.isMessage(s,t))throw new Error("Invalid site edit bridge message");return s}static stringifyMessage(e){return JSON.stringify(e)}static extractRequestInfo(e){if(typeof e=="object"&&e!==null&&"payload"in e&&typeof e.payload=="object"&&e.payload!==null){let t=e.payload,s=typeof t.id=="string"?t.id:"unknown",r=n.isRequestKind(t.kind)?t.kind:"get-document";return{id:s,kind:r}}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"?n.isRequestPayload(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:!1}static isRequestPayload(e,t={}){if(!h(e)||typeof e.id!="string"||!n.isRequestKind(e.kind))return!1;switch(e.kind){case"initialize-session":return typeof e.routeId=="string"&&(e.mutationContext===void 0||I(e.mutationContext));case"get-document":case"get-style-context":return typeof e.routeId=="string";case"get-object-edit-context":case"get-class-name-source":case"resolve-source-location":return typeof e.key=="string"&&(e.routeId===void 0||typeof e.routeId=="string");case"get-history-status":return e.mutationContext===void 0;case"get-source-tree":return!0;case"get-source-file":return typeof e.path=="string";case"execute":return R(e.request)&&(e.request.mutationContext===void 0||I(e.request.mutationContext))&&(t.validateOperationRequest?.(e.request)??!0);case"undo":case"redo":return e.mutationContext===void 0||I(e.mutationContext)}}};function h(n){return typeof n=="object"&&n!==null}function R(n){return h(n)&&typeof n.id=="string"&&typeof n.siteId=="string"&&typeof n.baseSnapshotId=="string"&&(n.routeId===void 0||typeof n.routeId=="string")&&typeof n.kind=="string"&&h(n.target)&&typeof n.documentVersion=="number"&&Number.isInteger(n.documentVersion)&&n.documentVersion>=0&&h(n.params)}function I(n){return T(n)}function T(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:!1}var A="vcp:designer:trace",_="designer_trace",k="__VCP_DESIGNER_TRACE__";var F=/(authorization|cookie|token|secret|providerTrace|headers?|sourceCode|rawSource|fullSource)/i;function K(n=globalThis){let e=n;try{if(e.localStorage?.getItem(A)==="1")return!0}catch{}try{let t=e.location?.search??"";return new URLSearchParams(t).get(_)==="1"}catch{return!1}}function l(n,e={},t=globalThis){if(!K(t))return;let s={type:n,timestamp:Date.now(),payload:j(e)},r=t,o=r[k]??[];o.push(s),o.length>1e3&&o.splice(0,o.length-1e3),r[k]=o;let a=t.console?.debug;s.payload.diagnosticOnly!==!0&&typeof a=="function"&&a.call(t.console,"[designer-trace]",s)}function j(n){return S(n,0)}function S(n,e){if(e>4)return"[truncated]";if(Array.isArray(n))return n.map(s=>S(s,e+1));if(!n||typeof n!="object")return n;let t={};for(let[s,r]of Object.entries(n)){if(F.test(s)){t[s]="[redacted]";continue}t[s]=S(r,e+1)}return t}var w=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===C&&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 s;try{s=this.createSocket(this.options.url)}catch(i){let c=m(i,"WebSocket failed");this.socket=null,this.connectAttempt=null,this.connectPromise=null,this.setConnectionState("failed",c.message),t(c);return}let r={socket:s,settled:!1,reject:t};this.connectAttempt=r,this.socket=s;let o=()=>{this.socket!==s||this.connectAttempt!==r||(r.settled=!0,this.connectAttempt=null,this.connectPromise=null,this.setConnectionState("open"),e())},a=(i,c)=>{this.cleanupSocket(s,i,c)};s.onopen=()=>{if(!(this.socket!==s||this.connectAttempt!==r)){if(this.options.authKey){try{s.send(p.stringifyMessage({type:"auth",payload:{key:this.options.authKey}}))}catch(i){a(m(i,"WebSocket auth failed"),"failed")}return}o()}},s.onerror=i=>{if(this.socket!==s)return;let c=m(i,"WebSocket failed");a(c,"failed")},s.onmessage=i=>{if(this.socket===s){if(this.options.authKey&&this.connectAttempt===r&&!r.settled){this.handleAuthHandshakeMessage(i.data,s,r,()=>{o()});return}this.handleMessage(i.data)}},s.onclose=i=>{if(this.socket!==s)return;let c=this.intentionalClose,d=new Error($(i,{intentional:c}));a(d,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){return this.request("get-document",{routeId:e})}initializeSession(e){return this.request("initialize-session",e)}getHistoryStatus(){return this.request("get-history-status",{})}getStyleContext(e){return this.request("get-style-context",{routeId:e})}getObjectEditContext(e,t){return this.request("get-object-edit-context",{key:e,routeId:t})}getClassNameSource(e,t){return this.request("get-class-name-source",{key:e,routeId:t})}getSourceTree(){return this.request("get-source-tree",{})}getSourceFile(e){return this.request("get-source-file",e)}resolveSourceLocation(e){return this.request("resolve-source-location",e)}execute(e,t){return this.request("execute",{request:e})}undo(e){return this.request("undo",{})}redo(e){return this.request("redo",{})}subscribe(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}request(e,t){let s=this.socket;if(!s||s.readyState!==C||this.connectionState!=="open")return Promise.reject(new Error(`WebSocket is not open (state: ${this.connectionState}, readyState: ${s?.readyState??"none"})`));let r=`${e}-${this.sequence+=1}`,o=v(r,e,t);return l("bridge.request",{id:r,kind:e,routeId:typeof t.routeId=="string"?t.routeId:null,key:typeof t.key=="string"?t.key:null,operationKind:E(t.request,"kind"),documentVersion:E(t.request,"documentVersion")}),new Promise((a,i)=>{let c=this.resolveRequestTimeoutMs(e),d=c>0?setTimeout(()=>{let u=this.pending.get(r);u&&(this.pending.delete(r),l("bridge.response",{id:r,kind:e,ok:!1,timedOut:!0}),u.reject(new Error(`Bridge request timed out after ${c}ms: ${e}`)))},c):null;d?.unref?.(),this.pending.set(r,{kind:e,timeout:d,resolve:u=>a(u),reject:i});try{s.send(p.stringifyMessage(o))}catch(u){let f=m(u,"WebSocket send failed");this.clearPendingRequest(r),i(f),this.cleanupSocket(s,f,"failed")}})}handleAuthHandshakeMessage(e,t,s,r){try{if(p.parseMessage(e).type==="auth-ok"){r();return}throw new Error("Bridge authentication failed")}catch(o){let a=m(o,"Bridge authentication failed");this.connectAttempt===s&&this.cleanupSocket(t,a,"failed")}}handleMessage(e){let t=p.parseMessage(e);if(t.type==="event"){for(let r of this.listeners)r(t.payload.event);return}if(t.type!=="response"&&t.type!=="error")return;let s=this.pending.get(t.payload.id);if(s){if(this.clearPendingRequest(t.payload.id),t.type==="error"){l("bridge.response",{id:t.payload.id,kind:s.kind,ok:!1}),s.reject(new Error(t.payload.message));return}l("bridge.response",{id:t.payload.id,kind:s.kind,ok:!0,resultVersion:P(t.payload.result)}),s.resolve(s.kind==="get-document"?{...t.payload.result,data:y(t.payload.result.data)}:s.kind==="initialize-session"?B(t.payload.result):t.payload.result)}}rejectAll(e){for(let[t,s]of[...this.pending])this.clearPendingRequest(t),s.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):U[e]??N}cleanupSocket(e,t,s){if(this.socket===e&&(this.socket=null),this.connectAttempt?.socket===e){let r=this.connectAttempt;this.connectAttempt=null,r.settled||(r.settled=!0,r.reject(t))}this.connectPromise=null,this.rejectAll(t),this.setConnectionState(s,t.message),e.onopen=null,e.onmessage=null,e.onerror=null,e.onclose=null;try{(e.readyState===O||e.readyState===C)&&e.close()}catch{}}setConnectionState(e,t){if(this.connectionState===e&&!t)return;this.connectionState=e;let s={state:e,...t?{message:t}:{}};this.options.onConnectionStatus?.(s);for(let r of this.connectionStatusListeners)r(s)}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)}},O=0,C=1,N=15e3,U={"get-source-tree":1e4,"get-source-file":1e4,"resolve-source-location":1e4,execute:6e4,undo:2e4,redo:2e4};function m(n,e){return n instanceof Error?n:new Error(e)}function $(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 E(n,e){if(!n||typeof n!="object")return null;let s=n[e];return typeof s=="string"||typeof s=="number"?s:null}function P(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 Y(n){return new b(n)}var b=class{constructor(e){this.params=e,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=null,this.styleContextInFlight=null,this.currentDocument=e.initialDocument,this.observedDocumentVersion=e.initialDocument.version,this.sessionInitialized=!q(e.initialDocument)}async getDocument(e){if(e!==this.params.routeId)throw new Error(`Site edit bridge is bound to route ${this.params.routeId}, received ${e}`);let t=q(this.currentDocument);return(t||this.currentDocument.version<this.observedDocumentVersion)&&(this.currentDocument=await this.refreshSnapshot(t?void 0:this.observedDocumentVersion,"get-document"),this.sessionInitialized=!0),{ok:!0,data:this.currentDocument}}async initializeSession(e){if(e.routeId!==this.params.routeId)throw new Error(`Site edit bridge is bound to route ${this.params.routeId}, received ${e.routeId}`);if(!this.params.client.initializeSession)throw new Error("Site edit bridge client does not support initialize-session");let t=await this.params.client.initializeSession(e);return this.currentDocument=t.data.document,this.observedDocumentVersion=t.data.document.version,this.sessionInitialized=!0,this.clearObjectCaches(),t}async getHistoryStatus(){return this.params.client.getHistoryStatus()}async getStyleContext(e){if(e!==this.params.routeId)throw new Error(`Site edit bridge is bound to route ${this.params.routeId}, received ${e}`);let t=this.styleContextCache;if(t?.generation===this.styleGeneration)return{ok:!0,data:t.value};let s=this.styleContextInFlight;if(s?.generation===this.styleGeneration)return s.request;let r=this.styleGeneration,o=this.params.client.getStyleContext(e).then(a=>(this.styleGeneration===r&&(this.styleContextCache={generation:r,value:a.data}),a)).finally(()=>{this.styleContextInFlight?.request===o&&(this.styleContextInFlight=null)});return this.styleContextInFlight={generation:r,request:o},o}async ensureDocumentVersion(e,t){if(e!==this.params.routeId)throw new Error(`Site edit bridge is bound to route ${this.params.routeId}, received ${e}`);let s=await this.refreshSnapshot(t,"ensure-version");if(s.version<t)throw new Error(`Document refresh returned version ${s.version}, expected at least ${t}`);return{ok:!0,data:s}}async acknowledgeDocumentVersion(e,t){if(e!==this.params.routeId)throw new Error(`Site edit bridge is bound to route ${this.params.routeId}, received ${e}`);return t>this.currentDocument.version&&(this.currentDocument={...this.currentDocument,version:t},this.clearObjectCaches({preserveStyleContext:!0})),this.observedDocumentVersion=Math.max(this.observedDocumentVersion,t),{ok:!0,data:this.currentDocument}}async getObjectEditContext(e,t){let s=this.objectCacheKey(e,t),r=this.editContextCache.get(s);if(r)return{ok:!0,data:r};let o=this.editContextInFlight.get(s);if(o)return o;let a=this.objectGeneration,i=this.params.client.getObjectEditContext(e,t??this.params.routeId).then(c=>(this.objectGeneration===a&&this.editContextCache.set(s,c.data),c)).finally(()=>{this.editContextInFlight.get(s)===i&&this.editContextInFlight.delete(s)});return this.editContextInFlight.set(s,i),i}async getClassNameSource(e,t){let s=this.objectCacheKey(e,t),r=this.classNameSourceCache.get(s);if(r)return r;let o=this.classNameSourceInFlight.get(s);if(o)return o;let a=this.objectGeneration,i=this.params.client.getClassNameSource(e,t??this.params.routeId).then(c=>(this.objectGeneration===a&&this.classNameSourceCache.set(s,c),c)).finally(()=>{this.classNameSourceInFlight.get(s)===i&&this.classNameSourceInFlight.delete(s)});return this.classNameSourceInFlight.set(s,i),i}async getSourceTree(){return this.params.client.getSourceTree()}async getSourceFile(e){return this.params.client.getSourceFile(e)}async resolveSourceLocation(e){return this.params.client.resolveSourceLocation({...e,routeId:e.routeId??this.params.routeId})}async execute(e,t){let s=e.target.kind==="node"&&!e.routeId?{...e,routeId:this.params.routeId}:e;return this.params.client.execute(s)}async undo(e){return this.params.client.undo()}async redo(e){return this.params.client.redo()}subscribe(e){return this.params.client.subscribe(t=>{if(t.type==="site-edit.document.changed"&&t.routeId===this.params.routeId&&this.sessionInitialized){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",{routeId:this.params.routeId,minVersion:e,currentVersion:this.currentDocument.version,deduped:!0,skipped:!0,source:t}),this.currentDocument;if(this.refreshInFlight){l("bridge.document-refresh",{routeId:this.params.routeId,minVersion:e,currentVersion:this.currentDocument.version,deduped:!0,source:t});let r=await this.refreshInFlight;if(typeof e!="number"||r.version>=e||this.currentDocument.version>=e)return this.currentDocument}l("bridge.document-refresh",{routeId:this.params.routeId,minVersion:e,currentVersion:this.currentDocument.version,deduped:!1,source:t});let s=this.params.client.getDocument(this.params.routeId).then(r=>(this.currentDocument=r.data,this.observedDocumentVersion=Math.max(this.observedDocumentVersion,r.data.version),this.clearObjectCaches(),this.currentDocument));this.refreshInFlight=s;try{return await s}finally{this.refreshInFlight===s&&(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=null,this.styleContextInFlight=null)}objectCacheKey(e,t){return`${t??this.params.routeId}\0${e}`}};function q(n){return n.version===0&&n.entries.length===0}function B(n){let e=n;return{...e,data:{...e.data,document:y(e.data.document)}}}function v(n,e,t){switch(e){case"initialize-session":return{type:"request",payload:{id:n,kind:e,routeId:String(t.routeId),...t.mutationContext?{mutationContext:t.mutationContext}:{}}};case"get-document":return{type:"request",payload:{id:n,kind:e,routeId:String(t.routeId)}};case"get-history-status":return{type:"request",payload:{id:n,kind:e}};case"get-style-context":return{type:"request",payload:{id:n,kind:e,routeId:String(t.routeId)}};case"get-object-edit-context":return{type:"request",payload:{id:n,kind:e,key:String(t.key),routeId:typeof t.routeId=="string"?t.routeId:void 0}};case"get-class-name-source":return{type:"request",payload:{id:n,kind:e,key:String(t.key),routeId:typeof t.routeId=="string"?t.routeId:void 0}};case"get-source-tree":return{type:"request",payload:{id:n,kind:e}};case"get-source-file":return{type:"request",payload:{id:n,kind:e,path:String(t.path)}};case"resolve-source-location":return{type:"request",payload:{id:n,kind:e,key:String(t.key),routeId:typeof t.routeId=="string"?t.routeId:void 0}};case"execute":return{type:"request",payload:{id:n,kind:e,request:t.request}};case"undo":case"redo":return{type:"request",payload:{id:n,kind:e,mutationContext:t.mutationContext}}}}export{w as SiteEditWebSocketClient,Y as createSiteEditBridge};
|
|
1
|
+
function q(n){if(!v(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:A(c),...o.get(r)?{dynamicDataSummary:o.get(r)}:{}}})}}function A(n){return{canUpdateText:(n&1)!==0,canInsertChild:(n&2)!==0,canMove:(n&4)!==0,canRemove:(n&8)!==0}}function v(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||!S(e.pageComposition)||!Array.isArray(e.tokens)||!e.tokens.every(s=>typeof s=="string")||!Array.isArray(e.nodes)||!Array.isArray(e.entries))return!1;let 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&&S(s[1]))}function S(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function K(n){return!S(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"?N(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 N(n,e){if(!d(n)||typeof n.id!="string"||!p.isRequestKind(n.kind))return!1;let t=b(n.composition);switch(n.kind){case"initialize-session":return t&&(n.mutationContext===void 0||x(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&&B(n.request)&&(n.request.mutationContext===void 0||x(n.request.mutationContext))&&(e.validateOperationRequest?.(n.request)??!0);case"undo":case"redo":return t&&n.mutationContext===void 0||t&&x(n.mutationContext)}}function B(n){return d(n)&&typeof n.id=="string"&&typeof n.siteId=="string"&&typeof n.baseSnapshotId=="string"&&b(n.composition)&&typeof n.kind=="string"&&d(n.target)&&(n.target.kind!=="route"||b(n.target.composition))&&typeof n.documentVersion=="number"&&Number.isInteger(n.documentVersion)&&n.documentVersion>=0&&d(n.params)}function b(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 x(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 F="vcp:designer:trace",j="designer_trace",T="__VCP_DESIGNER_TRACE__";var U=/(authorization|cookie|token|secret|providerTrace|headers?|sourceCode|rawSource|fullSource)/i;function P(n=globalThis){let e=n;try{if(e.localStorage?.getItem(F)==="1")return!0}catch{}try{let t=e.location?.search??"";return new URLSearchParams(t).get(j)==="1"}catch{return!1}}function l(n,e={},t=globalThis){if(!P(t))return;let o={type:n,timestamp:Date.now(),payload:W(e)},s=t,i=s[T]??[];i.push(o),i.length>1e3&&i.splice(0,i.length-1e3),s[T]=i;let r=t.console?.debug;o.payload.diagnosticOnly!==!0&&typeof r=="function"&&r.call(t.console,"[designer-trace]",o)}function W(n){return w(n,0)}function w(n,e){if(e>4)return"[truncated]";if(Array.isArray(n))return n.map(o=>w(o,e+1));if(!n||typeof n!="object")return n;let t={};for(let[o,s]of Object.entries(n)){if(U.test(o)){t[o]="[redacted]";continue}t[o]=w(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===E&&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(G(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=C(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!==E||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:R(t.request,"kind"),documentVersion:R(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:J(t.payload.result)}),o.resolve(o.kind==="get-document"?{...t.payload.result,data:M(t.payload.result.data,t.payload.result.composition)}:o.kind==="initialize-session"?V(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):L[e]??z}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===$||e.readyState===E)&&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)}},$=0,E=1,z=15e3,L={"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 G(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 R(n,e){if(!n||typeof n!="object")return null;let o=n[e];return typeof o=="string"||typeof o=="number"?o:null}function J(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 k({composition:e,initialDocument:n.initialDocument,client:n.client})}var k=class{constructor(e){this.params=e,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.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=!_(e.initialDocument),this.activeCompositionContext=this.sessionInitialized?{...e.initialDocument.composition}:null}async getDocument(e){this.requireBoundComposition(e);let t=_(this.currentDocument);return(t||this.currentDocument.version<this.observedDocumentVersion)&&(this.currentDocument=await this.refreshSnapshot(t?void 0:this.observedDocumentVersion,"get-document"),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.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=I(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=C(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.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=I(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.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`${I(t)}\0${e}`}requireBoundComposition(e){let t=e===void 0?this.composition:m(e);if(I(t)!==I(this.composition))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??Q(this.composition);return O(e)===O(t)}};function _(n){return n.version===0&&n.entries.length===0}function V(n){let e=n;return{...e,data:{...e.data,document:M(e.data.document,e.composition)}}}function M(n,e){let t=n,o=q(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 I(n){return JSON.stringify([n.routeId,n.templateId??null])}function O(n){return JSON.stringify([n.routeId,n.effectiveTemplateId??null])}function Q(n){return{routeId:n.routeId,...n.templateId?{effectiveTemplateId:n.templateId}:{}}}function C(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"?C(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:C(t.request)??o}}}}}export{D as SiteEditWebSocketClient,ie as createSiteEditBridge};
|
package/dist/document-codec.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ export type CompactRenderDocument = {
|
|
|
3
3
|
encoding: "segment-trie-v1";
|
|
4
4
|
siteId: string;
|
|
5
5
|
snapshotId: string;
|
|
6
|
+
/** The full composition identity must survive compact transport. */
|
|
7
|
+
composition: SiteEditRenderDocument["composition"];
|
|
6
8
|
routeId: string;
|
|
7
9
|
version: number;
|
|
8
10
|
pageComposition: SiteEditRenderDocument["pageComposition"];
|
package/dist/document-codec.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function
|
|
1
|
+
function M(e){let n=new Map,i=[],s=new Map,t=[],a=e.pageComposition.status==="supported"?e.pageComposition.placementUnitKeys:[],m=new Map(a.map((o,r)=>[o,r])),g=e.pageComposition.status==="supported"?{status:"supported",containerKey:e.pageComposition.containerKey,hasBusinessMembers:e.pageComposition.hasBusinessMembers,placementUnitKeys:e.pageComposition.placementUnitKeys,placements:e.pageComposition.placements.map(o=>({placementKey:o.placementKey,placementUnitKey:o.placementUnitKey,relation:o.relation}))}:{status:"unsupported",reason:e.pageComposition.reason,diagnostics:e.pageComposition.diagnostics},u=e.entries.flatMap((o,r)=>o.dynamicDataSummary?[[r,o.dynamicDataSummary]]:[]),p=o=>{let r=n.get(o);if(typeof r=="number")return r;let d=i.length;return i.push(o),n.set(o,d),d},c=o=>{let r=null;for(let d of A(o)){let l=`${r??"root"}\0${d}`,h=s.get(l);if(typeof h=="number"){r=h;continue}let I=t.length;t.push([r,p(d)]),s.set(l,I),r=I}if(r===null)throw new Error("Document key must not be empty");return r};return{encoding:"segment-trie-v1",siteId:e.siteId,snapshotId:e.snapshotId,composition:{...e.composition},routeId:e.composition.routeId,version:e.version,pageComposition:g,tokens:i,nodes:t,entries:e.entries.map(o=>{let r=o.pageCompositionUnitKey?m.get(o.pageCompositionUnitKey)??-1:-1;if(o.pageCompositionUnitKey&&r<0)throw new Error(`Render entry ${o.key} references unknown page composition unit ${o.pageCompositionUnitKey}`);return[c(o.key),K(o.operationSummary),...r>=0?[r]:[]]}),...u.length>0?{dynamicDataSummaries:u}:{}}}function S(e){if(!U(e))return e;let n=new Map,i=e.pageComposition.status==="supported"?e.pageComposition.placementUnitKeys:[],s=new Map(e.dynamicDataSummaries??[]),t=a=>{let m=n.get(a);if(m)return m;let g=e.nodes[a];if(!g)throw new Error(`Missing compact document node ${a}`);let[u,p]=g,c=e.tokens[p];if(typeof c!="string")throw new Error(`Missing compact document token ${p}`);let o=`${u===null?"":t(u)}${c}`;return n.set(a,o),o};return{siteId:e.siteId,snapshotId:e.snapshotId,composition:{...e.composition},routeId:e.composition.routeId,version:e.version,pageComposition:e.pageComposition,entries:e.entries.map((a,m)=>{let[g,u,p]=a,c=p===void 0?void 0:i[p];if(p!==void 0&&!c)throw new Error(`Missing page composition unit ${p}`);return{key:t(g),...c?{pageCompositionUnitKey:c}:{},operationSummary:x(u),...s.get(m)?{dynamicDataSummary:s.get(m)}:{}}})}}function K(e){return(e.canUpdateText?1:0)|(e.canInsertChild?2:0)|(e.canMove?4:0)|(e.canRemove?8:0)}function x(e){return{canUpdateText:(e&1)!==0,canInsertChild:(e&2)!==0,canMove:(e&4)!==0,canRemove:(e&8)!==0}}function U(e){if(typeof e!="object"||e===null)return!1;let n=e;if(n.encoding!=="segment-trie-v1"||typeof n.siteId!="string"||typeof n.snapshotId!="string"||!w(n.composition)||typeof n.routeId!="string"||n.routeId!==n.composition.routeId||!Number.isInteger(n.version)||n.version<0||!y(n.pageComposition)||!Array.isArray(n.tokens)||!n.tokens.every(t=>typeof t=="string")||!Array.isArray(n.nodes)||!Array.isArray(n.entries))return!1;let i=n.nodes;if(!i.every((t,a)=>Array.isArray(t)&&t.length===2&&(t[0]===null||f(t[0])&&t[0]<a)&&f(t[1])&&t[1]<n.tokens.length)||!n.entries.every(t=>Array.isArray(t)&&(t.length===2||t.length===3)&&f(t[0])&&t[0]<i.length&&f(t[1])&&t[1]<=15&&(t.length===2||f(t[2]))))return!1;let s=n.dynamicDataSummaries;return s===void 0||Array.isArray(s)&&s.every(t=>Array.isArray(t)&&t.length===2&&f(t[0])&&t[0]<n.entries.length&&y(t[1]))}function y(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function w(e){return!y(e)||typeof e.routeId!="string"?!1:e.effectiveTemplateId===void 0||typeof e.effectiveTemplateId=="string"}function f(e){return typeof e=="number"&&Number.isInteger(e)&&e>=0}function A(e){if(!e)return[];let n=[],i=0,s=C(e,i);if(s<0)return n.push(e),n;for(n.push(e.slice(0,s)),i=s;i<e.length;){if(s=C(e,i+(e.startsWith("::",i)?2:1)),s<0){n.push(e.slice(i));break}n.push(e.slice(i,s)),i=s}return n}function C(e,n){let i=e.indexOf("/",n),s=e.indexOf("::",n);return i<0?s:s<0?i:Math.min(i,s)}export{S as decodeRenderDocument,M as encodeRenderDocument,U as isCompactRenderDocument};
|