@vcp-dev/site-edit-bridge 0.6.3 → 0.6.5

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.
@@ -0,0 +1,419 @@
1
+ import { encodeRenderDocument, } from "./document-codec.js";
2
+ export class SiteEditBridgeTransport {
3
+ constructor() { }
4
+ static parseMessage(raw, options = {}) {
5
+ const parsed = JSON.parse(raw);
6
+ if (!SiteEditBridgeTransport.isMessage(parsed, options)) {
7
+ throw new Error("Invalid site edit bridge message");
8
+ }
9
+ return parsed;
10
+ }
11
+ static stringifyMessage(message) {
12
+ return JSON.stringify(message);
13
+ }
14
+ static extractRequestInfo(message) {
15
+ if (typeof message === "object" &&
16
+ message !== null &&
17
+ "payload" in message &&
18
+ typeof message.payload === "object" &&
19
+ message.payload !== null) {
20
+ const payload = message.payload;
21
+ const id = typeof payload.id === "string" ? payload.id : "unknown";
22
+ const kind = SiteEditBridgeTransport.isRequestKind(payload.kind)
23
+ ? payload.kind
24
+ : "get-document";
25
+ return { id, kind };
26
+ }
27
+ return { id: "unknown", kind: "get-document" };
28
+ }
29
+ static isRequestKind(value) {
30
+ return (value === "initialize-session" ||
31
+ value === "get-document" ||
32
+ value === "get-history-status" ||
33
+ value === "get-style-context" ||
34
+ value === "get-object-edit-context" ||
35
+ value === "get-class-name-source" ||
36
+ value === "get-source-tree" ||
37
+ value === "get-source-file" ||
38
+ value === "resolve-source-location" ||
39
+ value === "execute" ||
40
+ value === "undo" ||
41
+ value === "redo");
42
+ }
43
+ static isMessage(value, options = {}) {
44
+ if (!isRecord(value) || typeof value.type !== "string") {
45
+ return false;
46
+ }
47
+ if (value.type === "request") {
48
+ return SiteEditBridgeTransport.isRequestPayload(value.payload, options);
49
+ }
50
+ if (value.type === "response" || value.type === "error") {
51
+ return isRecord(value.payload) && typeof value.payload.id === "string";
52
+ }
53
+ if (value.type === "event") {
54
+ return isRecord(value.payload) && isRecord(value.payload.event);
55
+ }
56
+ if (value.type === "auth") {
57
+ return isRecord(value.payload) && typeof value.payload.key === "string";
58
+ }
59
+ if (value.type === "auth-ok") {
60
+ return isRecord(value.payload) && value.payload.ok === true;
61
+ }
62
+ return false;
63
+ }
64
+ static isRequestPayload(payload, options = {}) {
65
+ if (!isRecord(payload) ||
66
+ typeof payload.id !== "string" ||
67
+ !SiteEditBridgeTransport.isRequestKind(payload.kind)) {
68
+ return false;
69
+ }
70
+ switch (payload.kind) {
71
+ case "initialize-session":
72
+ return (typeof payload.routeId === "string" &&
73
+ (payload.mutationContext === undefined ||
74
+ isValidMutationContext(payload.mutationContext)));
75
+ case "get-document":
76
+ case "get-style-context":
77
+ return typeof payload.routeId === "string";
78
+ case "get-object-edit-context":
79
+ case "get-class-name-source":
80
+ case "resolve-source-location":
81
+ return (typeof payload.key === "string" &&
82
+ (payload.routeId === undefined || typeof payload.routeId === "string"));
83
+ case "get-history-status":
84
+ return payload.mutationContext === undefined;
85
+ case "get-source-tree":
86
+ return true;
87
+ case "get-source-file":
88
+ return typeof payload.path === "string";
89
+ case "execute":
90
+ return (isOperationRequestLike(payload.request) &&
91
+ (payload.request.mutationContext === undefined ||
92
+ isValidMutationContext(payload.request.mutationContext)) &&
93
+ (options.validateOperationRequest?.(payload.request) ?? true));
94
+ case "undo":
95
+ case "redo":
96
+ return (payload.mutationContext === undefined ||
97
+ isValidMutationContext(payload.mutationContext));
98
+ }
99
+ }
100
+ }
101
+ export class SiteEditBridgeSocketServer {
102
+ constructor(options) {
103
+ this.options = options;
104
+ this.messageQueue = new SerializedSiteEditMessageQueue();
105
+ this.eventDispatcher = new BufferedSiteEditEventDispatcher((message) => {
106
+ this.sendJson(message);
107
+ });
108
+ this.unsubscribe = options.engine.subscribe((event) => {
109
+ this.eventDispatcher.push(event);
110
+ });
111
+ options.socket.onmessage = (event) => {
112
+ try {
113
+ void this.messageQueue.enqueue(() => this.handleRawMessage(event.data));
114
+ }
115
+ catch (error) {
116
+ this.sendJson({
117
+ type: "error",
118
+ payload: {
119
+ id: "unknown",
120
+ kind: "get-document",
121
+ message: error instanceof Error ? error.message : "Bridge queue overflow",
122
+ },
123
+ });
124
+ options.socket.close(1013, "bridge busy");
125
+ }
126
+ };
127
+ options.socket.onclose = () => {
128
+ this.unsubscribe();
129
+ };
130
+ }
131
+ async handleMessage(message) {
132
+ try {
133
+ const parsed = message;
134
+ if (parsed.type !== "request") {
135
+ return;
136
+ }
137
+ const payload = parsed.payload;
138
+ const { id } = payload;
139
+ switch (payload.kind) {
140
+ case "initialize-session": {
141
+ const result = await this.options.engine.initializeSession({
142
+ routeId: payload.routeId,
143
+ ...(payload.mutationContext
144
+ ? { mutationContext: payload.mutationContext }
145
+ : {}),
146
+ });
147
+ this.sendJson({
148
+ type: "response",
149
+ payload: {
150
+ id,
151
+ kind: payload.kind,
152
+ result: {
153
+ ok: true,
154
+ data: {
155
+ document: encodeRenderDocument(result.data.document),
156
+ historyStatus: result.data.historyStatus,
157
+ },
158
+ },
159
+ },
160
+ });
161
+ return;
162
+ }
163
+ case "get-document":
164
+ this.sendJson({
165
+ type: "response",
166
+ payload: {
167
+ id,
168
+ kind: payload.kind,
169
+ result: {
170
+ ok: true,
171
+ data: encodeRenderDocument((await this.options.engine.getDocument(payload.routeId)).data),
172
+ },
173
+ },
174
+ });
175
+ return;
176
+ case "get-history-status":
177
+ this.sendJson({
178
+ type: "response",
179
+ payload: {
180
+ id,
181
+ kind: payload.kind,
182
+ result: await this.options.engine.getHistoryStatus(),
183
+ },
184
+ });
185
+ return;
186
+ case "get-style-context":
187
+ this.sendJson({
188
+ type: "response",
189
+ payload: {
190
+ id,
191
+ kind: payload.kind,
192
+ result: await this.options.engine.getStyleContext(payload.routeId),
193
+ },
194
+ });
195
+ return;
196
+ case "get-object-edit-context":
197
+ this.sendJson({
198
+ type: "response",
199
+ payload: {
200
+ id,
201
+ kind: payload.kind,
202
+ result: await this.options.engine.getObjectEditContext(payload.key, payload.routeId),
203
+ },
204
+ });
205
+ return;
206
+ case "get-class-name-source":
207
+ this.sendJson({
208
+ type: "response",
209
+ payload: {
210
+ id,
211
+ kind: payload.kind,
212
+ result: await this.options.engine.getClassNameSource(payload.key, payload.routeId),
213
+ },
214
+ });
215
+ return;
216
+ case "get-source-tree":
217
+ this.sendJson({
218
+ type: "response",
219
+ payload: {
220
+ id,
221
+ kind: payload.kind,
222
+ result: await this.options.engine.getSourceTree(),
223
+ },
224
+ });
225
+ return;
226
+ case "get-source-file":
227
+ this.sendJson({
228
+ type: "response",
229
+ payload: {
230
+ id,
231
+ kind: payload.kind,
232
+ result: await this.options.engine.getSourceFile({
233
+ path: payload.path,
234
+ }),
235
+ },
236
+ });
237
+ return;
238
+ case "resolve-source-location":
239
+ this.sendJson({
240
+ type: "response",
241
+ payload: {
242
+ id,
243
+ kind: payload.kind,
244
+ result: await this.options.engine.resolveSourceLocation({
245
+ key: payload.key,
246
+ routeId: payload.routeId,
247
+ }),
248
+ },
249
+ });
250
+ return;
251
+ case "execute": {
252
+ await this.handleBufferedOperation(id, payload.kind, () => this.options.engine.execute(payload.request));
253
+ return;
254
+ }
255
+ case "undo":
256
+ await this.handleBufferedOperation(id, payload.kind, () => this.options.engine.undo());
257
+ return;
258
+ case "redo":
259
+ await this.handleBufferedOperation(id, payload.kind, () => this.options.engine.redo());
260
+ return;
261
+ }
262
+ }
263
+ catch (error) {
264
+ const requestInfo = SiteEditBridgeTransport.extractRequestInfo(message);
265
+ this.sendJson({
266
+ type: "error",
267
+ payload: {
268
+ ...requestInfo,
269
+ message: getBridgeErrorMessage(error),
270
+ code: getBridgeErrorCode(error),
271
+ },
272
+ });
273
+ }
274
+ }
275
+ async handleRawMessage(raw) {
276
+ try {
277
+ await this.handleMessage(SiteEditBridgeTransport.parseMessage(raw, {
278
+ validateOperationRequest: this.options.validateOperationRequest,
279
+ }));
280
+ }
281
+ catch (error) {
282
+ const message = error instanceof Error ? error.message : "Invalid websocket message";
283
+ const requestInfo = extractRawRequestInfo(raw);
284
+ this.sendJson({
285
+ type: "error",
286
+ payload: { ...requestInfo, message },
287
+ });
288
+ }
289
+ }
290
+ sendJson(message) {
291
+ this.options.socket.send(SiteEditBridgeTransport.stringifyMessage(message));
292
+ }
293
+ async handleBufferedOperation(id, kind, operation) {
294
+ this.eventDispatcher.beginBuffering();
295
+ try {
296
+ const result = await operation();
297
+ this.sendJson({ type: "response", payload: { id, kind, result } });
298
+ this.eventDispatcher.flush();
299
+ }
300
+ catch (error) {
301
+ this.sendJson({
302
+ type: "error",
303
+ payload: {
304
+ id,
305
+ kind,
306
+ message: getBridgeErrorMessage(error),
307
+ code: getBridgeErrorCode(error),
308
+ },
309
+ });
310
+ this.eventDispatcher.flush();
311
+ }
312
+ }
313
+ }
314
+ class BufferedSiteEditEventDispatcher {
315
+ constructor(send) {
316
+ this.send = send;
317
+ this.bufferedEvents = null;
318
+ }
319
+ push(event) {
320
+ const message = {
321
+ type: "event",
322
+ payload: { event },
323
+ };
324
+ if (this.bufferedEvents) {
325
+ this.bufferedEvents.push(message);
326
+ return;
327
+ }
328
+ this.send(message);
329
+ }
330
+ beginBuffering() {
331
+ this.bufferedEvents = [];
332
+ }
333
+ flush() {
334
+ const buffered = this.bufferedEvents ?? [];
335
+ this.bufferedEvents = null;
336
+ buffered.forEach((message) => {
337
+ this.send(message);
338
+ });
339
+ }
340
+ }
341
+ class SerializedSiteEditMessageQueue {
342
+ constructor(maxQueued = 64) {
343
+ this.maxQueued = maxQueued;
344
+ this.queue = Promise.resolve();
345
+ this.queued = 0;
346
+ }
347
+ enqueue(task) {
348
+ if (this.queued >= this.maxQueued) {
349
+ throw new Error("Bridge request queue is full");
350
+ }
351
+ this.queued += 1;
352
+ const run = async () => {
353
+ this.queued -= 1;
354
+ await task();
355
+ };
356
+ const next = this.queue.then(run, run);
357
+ this.queue = next.then(() => undefined, () => undefined);
358
+ return next;
359
+ }
360
+ }
361
+ function isRecord(value) {
362
+ return typeof value === "object" && value !== null;
363
+ }
364
+ function isOperationRequestLike(value) {
365
+ return (isRecord(value) &&
366
+ typeof value.id === "string" &&
367
+ typeof value.siteId === "string" &&
368
+ typeof value.baseSnapshotId === "string" &&
369
+ (value.routeId === undefined || typeof value.routeId === "string") &&
370
+ typeof value.kind === "string" &&
371
+ isRecord(value.target) &&
372
+ typeof value.documentVersion === "number" &&
373
+ Number.isInteger(value.documentVersion) &&
374
+ value.documentVersion >= 0 &&
375
+ isRecord(value.params));
376
+ }
377
+ function isValidMutationContext(value) {
378
+ return isMutationContextLike(value);
379
+ }
380
+ function getBridgeErrorCode(error) {
381
+ if (!error || typeof error !== "object") {
382
+ return undefined;
383
+ }
384
+ const code = error.code;
385
+ return typeof code === "string" && code.length > 0 ? code : undefined;
386
+ }
387
+ function getBridgeErrorMessage(error) {
388
+ if (error instanceof Error) {
389
+ return error.message;
390
+ }
391
+ if (!error || typeof error !== "object") {
392
+ return "Unknown websocket operation failure";
393
+ }
394
+ const message = error.message;
395
+ return typeof message === "string" && message.length > 0
396
+ ? message
397
+ : "Unknown websocket operation failure";
398
+ }
399
+ function isMutationContextLike(value) {
400
+ if (!isRecord(value)) {
401
+ return false;
402
+ }
403
+ return (typeof value.editingSessionId === "string" &&
404
+ value.editingSessionId.length > 0 &&
405
+ typeof value.lockId === "string" &&
406
+ value.lockId.length > 0 &&
407
+ typeof value.ownerId === "string" &&
408
+ value.ownerId.length > 0 &&
409
+ typeof value.leaseAssertion === "string" &&
410
+ value.leaseAssertion.length > 0);
411
+ }
412
+ function extractRawRequestInfo(raw) {
413
+ try {
414
+ return SiteEditBridgeTransport.extractRequestInfo(JSON.parse(raw));
415
+ }
416
+ catch {
417
+ return { id: "unknown", kind: "get-document" };
418
+ }
419
+ }
@@ -0,0 +1,74 @@
1
+ import { startSiteEditNextDevServer } from "./next-dev-server.js";
2
+ export async function runStartNextDevServerCli(argv, dependencies = {}) {
3
+ const env = dependencies.env ?? process.env;
4
+ const input = parseInput(argv);
5
+ const port = readPort(input.port ?? env.PORT ?? env.VCP_PREVIEW_PORT, 3000);
6
+ const host = input.host ?? env.HOST ?? "0.0.0.0";
7
+ const projectRoot = input.projectRoot ?? (dependencies.cwd ?? process.cwd)();
8
+ const preview = await (dependencies.startServer ?? startSiteEditNextDevServer)({
9
+ host,
10
+ port,
11
+ projectRoot,
12
+ siteId: env.VCP_SITE_ID ?? "site_preview",
13
+ snapshotId: env.VCP_SNAPSHOT_ID,
14
+ });
15
+ (dependencies.log ?? console.log)(JSON.stringify({
16
+ status: "ready",
17
+ kind: "site-edit-next-dev-server",
18
+ projectRoot,
19
+ preview_url: `http://127.0.0.1:${preview.port}`,
20
+ bridge_path: "/__vcp/site-edit/bridge",
21
+ bundler: preview.bundler,
22
+ }, null, 2));
23
+ return preview;
24
+ }
25
+ export async function main(argv, dependencies = {}) {
26
+ try {
27
+ await runStartNextDevServerCli(argv, dependencies);
28
+ }
29
+ catch (error) {
30
+ (dependencies.error ?? console.error)(error);
31
+ (dependencies.setExitCode ?? ((exitCode) => (process.exitCode = exitCode)))(1);
32
+ }
33
+ }
34
+ export function parseInput(argv) {
35
+ const input = {};
36
+ for (let index = 0; index < argv.length; index += 1) {
37
+ const arg = argv[index];
38
+ switch (arg) {
39
+ case "--host":
40
+ input.host = readValue(argv, (index += 1), arg);
41
+ break;
42
+ case "--port":
43
+ input.port = readValue(argv, (index += 1), arg);
44
+ break;
45
+ case "--project-root":
46
+ input.projectRoot = readValue(argv, (index += 1), arg);
47
+ break;
48
+ default:
49
+ throw new Error(`Unknown option: ${arg}`);
50
+ }
51
+ }
52
+ return input;
53
+ }
54
+ function readValue(argv, index, optionName) {
55
+ const value = argv[index];
56
+ if (!value ||
57
+ (value.startsWith("-") && !(optionName === "--port" && /^-\d/.test(value)))) {
58
+ throw new Error(`${optionName} requires a value.`);
59
+ }
60
+ return value;
61
+ }
62
+ export function readPort(value, fallback) {
63
+ if (value === undefined || value.trim() === "") {
64
+ return fallback;
65
+ }
66
+ if (!/^(?:0|[1-9]\d*)$/.test(value)) {
67
+ throw new Error(`Invalid port: ${value}. Expected an integer from 0 to 65535.`);
68
+ }
69
+ const parsed = Number(value);
70
+ if (parsed > 65_535) {
71
+ throw new Error(`Invalid port: ${value}. Expected an integer from 0 to 65535.`);
72
+ }
73
+ return parsed;
74
+ }
@@ -1,83 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import { pathToFileURL } from "node:url";
3
- import { startSiteEditNextDevServer } from "./next-dev-server.js";
4
- export async function runStartNextDevServerCli(argv, dependencies = {}) {
5
- const env = dependencies.env ?? process.env;
6
- const input = parseInput(argv);
7
- const port = readPort(input.port ?? env.PORT ?? env.VCP_PREVIEW_PORT, 3000);
8
- const host = input.host ?? env.HOST ?? "0.0.0.0";
9
- const projectRoot = input.projectRoot ?? (dependencies.cwd ?? process.cwd)();
10
- const preview = await (dependencies.startServer ?? startSiteEditNextDevServer)({
11
- host,
12
- port,
13
- projectRoot,
14
- siteId: env.VCP_SITE_ID ?? "site_preview",
15
- snapshotId: env.VCP_SNAPSHOT_ID,
16
- });
17
- (dependencies.log ?? console.log)(JSON.stringify({
18
- status: "ready",
19
- kind: "site-edit-next-dev-server",
20
- projectRoot: projectRoot,
21
- preview_url: `http://127.0.0.1:${preview.port}`,
22
- bridge_path: "/__vcp/site-edit/bridge",
23
- bundler: preview.bundler,
24
- }, null, 2));
25
- return preview;
26
- }
27
- export async function main(argv, dependencies = {}) {
28
- try {
29
- await runStartNextDevServerCli(argv, dependencies);
30
- }
31
- catch (error) {
32
- (dependencies.error ?? console.error)(error);
33
- (dependencies.setExitCode ?? ((exitCode) => (process.exitCode = exitCode)))(1);
34
- }
35
- }
36
- export function parseInput(argv) {
37
- const input = {};
38
- for (let index = 0; index < argv.length; index += 1) {
39
- const arg = argv[index];
40
- switch (arg) {
41
- case "--host":
42
- input.host = readValue(argv, (index += 1), arg);
43
- break;
44
- case "--port":
45
- input.port = readValue(argv, (index += 1), arg);
46
- break;
47
- case "--project-root":
48
- input.projectRoot = readValue(argv, (index += 1), arg);
49
- break;
50
- default:
51
- throw new Error(`Unknown option: ${arg}`);
52
- }
53
- }
54
- return input;
55
- }
56
- function readValue(argv, index, optionName) {
57
- const value = argv[index];
58
- if (!value ||
59
- (value.startsWith("-") && !(optionName === "--port" && /^-\d/.test(value)))) {
60
- throw new Error(`${optionName} requires a value.`);
61
- }
62
- return value;
63
- }
64
- export function readPort(value, fallback) {
65
- if (value === undefined || value.trim() === "") {
66
- return fallback;
67
- }
68
- if (!/^(?:0|[1-9]\d*)$/.test(value)) {
69
- throw new Error(`Invalid port: ${value}. Expected an integer from 0 to 65535.`);
70
- }
71
- const parsed = Number(value);
72
- if (parsed > 65_535) {
73
- throw new Error(`Invalid port: ${value}. Expected an integer from 0 to 65535.`);
74
- }
75
- return parsed;
76
- }
77
- function isMainModule() {
78
- const entryPath = process.argv[1];
79
- return Boolean(entryPath && import.meta.url === pathToFileURL(entryPath).href);
80
- }
81
- if (isMainModule()) {
82
- void main(process.argv.slice(2));
83
- }
2
+ import { main } from "./start-next-dev-server-cli.js";
3
+ void main(process.argv.slice(2));
@@ -37,7 +37,7 @@ export type SiteEditFrameRuntimeScrollMetrics = {
37
37
  viewportWidth: number;
38
38
  viewportHeight: number;
39
39
  };
40
- export type SiteEditFrameRuntimePointerEventKind = "pointer-down" | "pointer-move" | "pointer-up" | "pointer-cancel" | "pointer-click" | "pointer-double-click";
40
+ export type SiteEditFrameRuntimePointerEventKind = "pointer-down" | "pointer-move" | "pointer-leave" | "pointer-up" | "pointer-cancel" | "pointer-click" | "pointer-double-click";
41
41
  export type SiteEditFrameRuntimeNodePatch = {
42
42
  attributes?: Record<string, string | null>;
43
43
  className?: string;
@@ -292,6 +292,22 @@ export type SiteEditFrameRuntimeChildBox = {
292
292
  rect: SiteEditFrameRuntimeRect;
293
293
  margin: SiteEditFrameRuntimeMargin;
294
294
  };
295
+ export type SiteEditFrameRuntimeSectionContext = {
296
+ blockId: string;
297
+ ref: SiteEditFrameRuntimeRef;
298
+ rect: SiteEditFrameRuntimeRect;
299
+ targetIsSectionRoot: boolean;
300
+ };
301
+ export type SiteEditFrameRuntimeSectionGapCandidate = {
302
+ anchorBlockId: string;
303
+ anchorRef: SiteEditFrameRuntimeRef;
304
+ placement: "before" | "after";
305
+ boundary: {
306
+ top: number;
307
+ left: number;
308
+ width: number;
309
+ };
310
+ };
295
311
  export type SiteEditFrameRuntimeHit = {
296
312
  ref: SiteEditFrameRuntimeRef;
297
313
  key: string;
@@ -380,6 +396,8 @@ export type SiteEditFrameRuntimeEventBody = {
380
396
  clientY: number;
381
397
  buttons?: number;
382
398
  hit: SiteEditFrameRuntimeHit | null;
399
+ section: SiteEditFrameRuntimeSectionContext | null;
400
+ sectionGap: SiteEditFrameRuntimeSectionGapCandidate | null;
383
401
  };
384
402
  } | {
385
403
  type: "event";
@@ -1 +1 @@
1
- var l="vcp-window-message",T=1;function I(e){return{source:l,version:1,namespace:e.namespace,channel:e.channel,...e.sessionKey?{sessionKey:e.sessionKey}:{},body:e.body}}function x(e){try{return s(e)?d(e,"source",l)&&d(e,"version",1)&&i(e,"namespace")&&i(e,"channel")&&a(e,"body")&&(!u(e,"sessionKey")||i(e,"sessionKey")):!1}catch{return!1}}var m="site-edit",h="frame-runtime";function q(e,r={}){return I({namespace:m,channel:h,sessionKey:r.sessionKey,body:e})}function B(e){try{return!x(e)||e.namespace!==m||e.channel!==h?!1:C(e.body)}catch{return!1}}var u=(e,r)=>Object.prototype.hasOwnProperty.call(e,r);function a(e,r){let t=Object.getOwnPropertyDescriptor(e,r);return t!==void 0&&"value"in t}function n(e,r){return Object.getOwnPropertyDescriptor(e,r)?.value}function d(e,r,t){return a(e,r)&&n(e,r)===t}function i(e,r){return a(e,r)&&typeof n(e,r)=="string"}function E(e,r){return a(e,r)&&typeof n(e,r)=="boolean"}function o(e,r){let t=n(e,r);return a(e,r)&&typeof t=="number"&&Number.isFinite(t)}function y(e,r){return!u(e,r)||n(e,r)===void 0||i(e,r)}function p(e,r){return!u(e,r)||n(e,r)===void 0||o(e,r)}function b(e,r){let t=n(e,r);return!u(e,r)||t===void 0||a(e,r)&&typeof t=="number"&&Number.isInteger(t)&&t>=0}function c(e,r){return!u(e,r)||n(e,r)===void 0}function s(e){if(typeof e!="object"||e===null||Array.isArray(e))return!1;let r=Object.getPrototypeOf(e);return r===Object.prototype||r===null}function N(e){return s(e)&&Reflect.ownKeys(e).length===0}function w(e){if(!Array.isArray(e))return!1;for(let r=0;r<e.length;r+=1){let t=Object.getOwnPropertyDescriptor(e,String(r));if(t===void 0||!("value"in t)||typeof t.value!="string")return!1}return!0}function g(e){return s(e)&&i(e,"key")&&b(e,"instanceIndex")&&b(e,"instanceCount")&&b(e,"textSegmentIndex")}function R(e){return s(e)&&Reflect.ownKeys(e).every(r=>typeof r=="string"&&a(e,r)&&(typeof n(e,r)=="string"||n(e,r)===null))}function O(e){return e==null||typeof e=="string"||typeof e=="number"&&Number.isFinite(e)}function _(e){return s(e)&&Reflect.ownKeys(e).every(r=>typeof r=="string"&&a(e,r)&&O(n(e,r)))}function A(e){if(!s(e))return!1;let r=n(e,"priority");return i(e,"property")&&a(e,"value")&&O(n(e,"value"))&&(!u(e,"priority")||r===void 0||r==="important")}function P(e){return s(e)?(c(e,"attributes")||R(n(e,"attributes")))&&y(e,"className")&&(c(e,"style")||_(n(e,"style")))&&(c(e,"styleDeclarations")||Array.isArray(n(e,"styleDeclarations"))&&n(e,"styleDeclarations").every(A)):!1}function D(e){return s(e)&&o(e,"x")&&o(e,"y")&&(c(e,"detailLevel")||d(e,"detailLevel","summary")||d(e,"detailLevel","full"))}function V(e){return s(e)&&g(n(e,"ref"))}function K(e){if(!s(e)||!s(n(e,"variables")))return!1;let r=n(e,"variables");return Reflect.ownKeys(r).every(t=>typeof t=="string"&&i(r,t))?c(e,"stylesheets")||w(n(e,"stylesheets")):!1}function W(e){if(!d(e,"type","request")||!i(e,"id")||!i(e,"kind")||!a(e,"payload"))return!1;let r=n(e,"kind"),t=n(e,"payload");switch(r){case"hit-test-at-point":case"start-text-edit-at-point":return D(t);case"bridge-get-source-tree":case"get-scroll-metrics":case"clear-theme-override":case"bridge-get-history-status":case"bridge-undo":case"bridge-redo":return N(t);case"bridge-get-source-file":return s(t)&&i(t,"path");case"bridge-resolve-source-location":case"bridge-get-object-edit-context":case"bridge-get-class-name-source":return s(t)&&i(t,"key")&&y(t,"routeId");case"scroll-to":return s(t)&&o(t,"x")&&o(t,"y");case"scroll-by":return s(t)&&o(t,"deltaX")&&o(t,"deltaY");case"set-interaction-mode":return s(t)&&E(t,"enabled");case"set-theme-override":return K(t);case"get-theme-variables":return s(t)&&w(n(t,"names"));case"compute-drop-target-at-point":return s(t)&&o(t,"x")&&o(t,"y")&&(d(t,"dragKind","insert")||d(t,"dragKind","move"))&&(c(t,"movingRef")||g(n(t,"movingRef")));case"observe-node-bounds":case"clear-node-bounds-observer":return s(t)&&(c(t,"ref")||g(n(t,"ref")));case"apply-node-patch":return s(t)&&g(n(t,"ref"))&&P(n(t,"patch"))&&(c(t,"preview")||s(n(t,"preview"))&&i(n(t,"preview"),"sessionId")&&b(n(t,"preview"),"revision")&&u(n(t,"preview"),"revision"));case"get-hit-by-ref":case"get-path-by-ref":case"restore-text-edit":case"clear-text-edit-rollback":return V(t);case"bridge-initialize-session":case"bridge-get-style-context":return s(t)&&i(t,"routeId");case"bridge-get-document":case"bridge-ensure-document-version":case"bridge-acknowledge-document-version":return s(t)&&i(t,"routeId")&&p(t,"minVersion")&&p(t,"version");case"bridge-execute":return s(t)&&s(n(t,"request"));case"bridge-subscribe":case"bridge-unsubscribe":return s(t)&&i(t,"subscriptionId");default:return!1}}function M(e){return d(e,"type","response")&&i(e,"id")&&E(e,"ok")&&(c(e,"error")||i(e,"error"))}var F=new Set(["pointer-down","pointer-move","pointer-up","pointer-cancel","pointer-click","pointer-double-click"]);function j(e){if(!d(e,"type","event")||!i(e,"kind")||!s(n(e,"payload")))return!1;let r=n(e,"kind"),t=n(e,"payload");switch(r){case"text-edit-commit":case"text-edit-cancel":case"text-edit-exit":case"text-edit-input":return g(n(t,"ref"))&&y(t,"value")&&(c(t,"hit")||s(n(t,"hit")));case"node-bounds-change":return s(n(t,"hit"));case"bridge-event":return i(t,"subscriptionId")&&s(n(t,"event"));case"route-ready":return i(t,"routeId")&&p(t,"version");case"bridge-status":{let f=n(t,"state");return(f==="connecting"||f==="ready"||f==="reconnecting"||f==="failed"||f==="reload-required")&&y(t,"routeId")&&p(t,"attempt")&&p(t,"retryInMs")&&y(t,"messageKey")}case"scroll":{let f=n(t,"metrics");return s(f)&&["scrollX","scrollY","scrollWidth","scrollHeight","viewportWidth","viewportHeight"].every(S=>o(f,S))}default:return F.has(r)&&o(t,"clientX")&&o(t,"clientY")&&p(t,"buttons")&&(n(t,"hit")===null||s(n(t,"hit")))}}function C(e){if(!s(e))return!1;switch(n(e,"type")){case"request":return W(e);case"response":return M(e);case"event":return j(e);default:return!1}}export{h as SITE_EDIT_FRAME_RUNTIME_CHANNEL,m as SITE_EDIT_WINDOW_MESSAGE_NAMESPACE,l as VCP_WINDOW_MESSAGE_SOURCE,T as VCP_WINDOW_MESSAGE_VERSION,q as createSiteEditFrameRuntimeMessage,I as createVcpWindowMessageEnvelope,B as isSiteEditFrameRuntimeMessage,x as isVcpWindowMessageEnvelope};
1
+ var l="vcp-window-message",q=1;function I(e){return{source:l,version:1,namespace:e.namespace,channel:e.channel,...e.sessionKey?{sessionKey:e.sessionKey}:{},body:e.body}}function R(e){try{return i(e)?d(e,"source",l)&&d(e,"version",1)&&s(e,"namespace")&&s(e,"channel")&&a(e,"body")&&(!u(e,"sessionKey")||s(e,"sessionKey")):!1}catch{return!1}}var h="site-edit",w="frame-runtime";function L(e,r={}){return I({namespace:h,channel:w,sessionKey:r.sessionKey,body:e})}function H(e){try{return!R(e)||e.namespace!==h||e.channel!==w?!1:B(e.body)}catch{return!1}}var u=(e,r)=>Object.prototype.hasOwnProperty.call(e,r);function a(e,r){let t=Object.getOwnPropertyDescriptor(e,r);return t!==void 0&&"value"in t}function n(e,r){return Object.getOwnPropertyDescriptor(e,r)?.value}function d(e,r,t){return a(e,r)&&n(e,r)===t}function s(e,r){return a(e,r)&&typeof n(e,r)=="string"}function m(e,r){return a(e,r)&&typeof n(e,r)=="boolean"}function o(e,r){let t=n(e,r);return a(e,r)&&typeof t=="number"&&Number.isFinite(t)}function g(e,r){return!u(e,r)||n(e,r)===void 0||s(e,r)}function y(e,r){return!u(e,r)||n(e,r)===void 0||o(e,r)}function b(e,r){let t=n(e,r);return!u(e,r)||t===void 0||a(e,r)&&typeof t=="number"&&Number.isInteger(t)&&t>=0}function c(e,r){return!u(e,r)||n(e,r)===void 0}function i(e){if(typeof e!="object"||e===null||Array.isArray(e))return!1;let r=Object.getPrototypeOf(e);return r===Object.prototype||r===null}function x(e){return i(e)&&Reflect.ownKeys(e).length===0}function S(e){if(!Array.isArray(e))return!1;for(let r=0;r<e.length;r+=1){let t=Object.getOwnPropertyDescriptor(e,String(r));if(t===void 0||!("value"in t)||typeof t.value!="string")return!1}return!0}function p(e){return i(e)&&s(e,"key")&&b(e,"instanceIndex")&&b(e,"instanceCount")&&b(e,"textSegmentIndex")}function N(e){return i(e)&&o(e,"top")&&o(e,"left")&&o(e,"width")&&o(e,"height")}function _(e){return i(e)&&s(e,"blockId")&&p(n(e,"ref"))&&N(n(e,"rect"))&&m(e,"targetIsSectionRoot")}function A(e){if(!i(e))return!1;let r=n(e,"placement"),t=n(e,"boundary");return s(e,"anchorBlockId")&&p(n(e,"anchorRef"))&&(r==="before"||r==="after")&&i(t)&&o(t,"top")&&o(t,"left")&&o(t,"width")}function P(e){return i(e)&&Reflect.ownKeys(e).every(r=>typeof r=="string"&&a(e,r)&&(typeof n(e,r)=="string"||n(e,r)===null))}function E(e){return e==null||typeof e=="string"||typeof e=="number"&&Number.isFinite(e)}function D(e){return i(e)&&Reflect.ownKeys(e).every(r=>typeof r=="string"&&a(e,r)&&E(n(e,r)))}function V(e){if(!i(e))return!1;let r=n(e,"priority");return s(e,"property")&&a(e,"value")&&E(n(e,"value"))&&(!u(e,"priority")||r===void 0||r==="important")}function K(e){return i(e)?(c(e,"attributes")||P(n(e,"attributes")))&&g(e,"className")&&(c(e,"style")||D(n(e,"style")))&&(c(e,"styleDeclarations")||Array.isArray(n(e,"styleDeclarations"))&&n(e,"styleDeclarations").every(V)):!1}function W(e){return i(e)&&o(e,"x")&&o(e,"y")&&(c(e,"detailLevel")||d(e,"detailLevel","summary")||d(e,"detailLevel","full"))}function M(e){return i(e)&&p(n(e,"ref"))}function F(e){if(!i(e)||!i(n(e,"variables")))return!1;let r=n(e,"variables");return Reflect.ownKeys(r).every(t=>typeof t=="string"&&s(r,t))?c(e,"stylesheets")||S(n(e,"stylesheets")):!1}function C(e){if(!d(e,"type","request")||!s(e,"id")||!s(e,"kind")||!a(e,"payload"))return!1;let r=n(e,"kind"),t=n(e,"payload");switch(r){case"hit-test-at-point":case"start-text-edit-at-point":return W(t);case"bridge-get-source-tree":case"get-scroll-metrics":case"clear-theme-override":case"bridge-get-history-status":case"bridge-undo":case"bridge-redo":return x(t);case"bridge-get-source-file":return i(t)&&s(t,"path");case"bridge-resolve-source-location":case"bridge-get-object-edit-context":case"bridge-get-class-name-source":return i(t)&&s(t,"key")&&g(t,"routeId");case"scroll-to":return i(t)&&o(t,"x")&&o(t,"y");case"scroll-by":return i(t)&&o(t,"deltaX")&&o(t,"deltaY");case"set-interaction-mode":return i(t)&&m(t,"enabled");case"set-theme-override":return F(t);case"get-theme-variables":return i(t)&&S(n(t,"names"));case"compute-drop-target-at-point":return i(t)&&o(t,"x")&&o(t,"y")&&(d(t,"dragKind","insert")||d(t,"dragKind","move"))&&(c(t,"movingRef")||p(n(t,"movingRef")));case"observe-node-bounds":case"clear-node-bounds-observer":return i(t)&&(c(t,"ref")||p(n(t,"ref")));case"apply-node-patch":return i(t)&&p(n(t,"ref"))&&K(n(t,"patch"))&&(c(t,"preview")||i(n(t,"preview"))&&s(n(t,"preview"),"sessionId")&&b(n(t,"preview"),"revision")&&u(n(t,"preview"),"revision"));case"get-hit-by-ref":case"get-path-by-ref":case"restore-text-edit":case"clear-text-edit-rollback":return M(t);case"bridge-initialize-session":case"bridge-get-style-context":return i(t)&&s(t,"routeId");case"bridge-get-document":case"bridge-ensure-document-version":case"bridge-acknowledge-document-version":return i(t)&&s(t,"routeId")&&y(t,"minVersion")&&y(t,"version");case"bridge-execute":return i(t)&&i(n(t,"request"));case"bridge-subscribe":case"bridge-unsubscribe":return i(t)&&s(t,"subscriptionId");default:return!1}}function j(e){return d(e,"type","response")&&s(e,"id")&&m(e,"ok")&&(c(e,"error")||s(e,"error"))}var G=new Set(["pointer-down","pointer-move","pointer-leave","pointer-up","pointer-cancel","pointer-click","pointer-double-click"]);function T(e){if(!d(e,"type","event")||!s(e,"kind")||!i(n(e,"payload")))return!1;let r=n(e,"kind"),t=n(e,"payload");switch(r){case"text-edit-commit":case"text-edit-cancel":case"text-edit-exit":case"text-edit-input":return p(n(t,"ref"))&&g(t,"value")&&(c(t,"hit")||i(n(t,"hit")));case"node-bounds-change":return i(n(t,"hit"));case"bridge-event":return s(t,"subscriptionId")&&i(n(t,"event"));case"route-ready":return s(t,"routeId")&&y(t,"version");case"bridge-status":{let f=n(t,"state");return(f==="connecting"||f==="ready"||f==="reconnecting"||f==="failed"||f==="reload-required")&&g(t,"routeId")&&y(t,"attempt")&&y(t,"retryInMs")&&g(t,"messageKey")}case"scroll":{let f=n(t,"metrics");return i(f)&&["scrollX","scrollY","scrollWidth","scrollHeight","viewportWidth","viewportHeight"].every(O=>o(f,O))}default:return G.has(r)&&o(t,"clientX")&&o(t,"clientY")&&y(t,"buttons")&&(n(t,"hit")===null||i(n(t,"hit")))&&(n(t,"section")===null||_(n(t,"section")))&&(n(t,"sectionGap")===null||A(n(t,"sectionGap")))}}function B(e){if(!i(e))return!1;switch(n(e,"type")){case"request":return C(e);case"response":return j(e);case"event":return T(e);default:return!1}}export{w as SITE_EDIT_FRAME_RUNTIME_CHANNEL,h as SITE_EDIT_WINDOW_MESSAGE_NAMESPACE,l as VCP_WINDOW_MESSAGE_SOURCE,q as VCP_WINDOW_MESSAGE_VERSION,L as createSiteEditFrameRuntimeMessage,I as createVcpWindowMessageEnvelope,H as isSiteEditFrameRuntimeMessage,R as isVcpWindowMessageEnvelope};