@forgecart/designer-runtime 1.0.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.
Files changed (57) hide show
  1. package/README.md +166 -0
  2. package/dist/index.d.ts +10 -0
  3. package/dist/index.js +51 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/loader-cjs/package.json +3 -0
  6. package/dist/loader-cjs/turbo-loader.d.ts +13 -0
  7. package/dist/loader-cjs/turbo-loader.js +190 -0
  8. package/dist/loader-cjs/turbo-loader.js.map +1 -0
  9. package/dist/protocol/element-reference-formatter.d.ts +28 -0
  10. package/dist/protocol/element-reference-formatter.js +60 -0
  11. package/dist/protocol/element-reference-formatter.js.map +1 -0
  12. package/dist/protocol/element.types.d.ts +75 -0
  13. package/dist/protocol/element.types.js +7 -0
  14. package/dist/protocol/element.types.js.map +1 -0
  15. package/dist/protocol/index.d.ts +5 -0
  16. package/dist/protocol/index.js +6 -0
  17. package/dist/protocol/index.js.map +1 -0
  18. package/dist/protocol/message-codec.d.ts +50 -0
  19. package/dist/protocol/message-codec.js +209 -0
  20. package/dist/protocol/message-codec.js.map +1 -0
  21. package/dist/protocol/message.types.d.ts +122 -0
  22. package/dist/protocol/message.types.js +2 -0
  23. package/dist/protocol/message.types.js.map +1 -0
  24. package/dist/protocol/protocol.constant.d.ts +30 -0
  25. package/dist/protocol/protocol.constant.js +31 -0
  26. package/dist/protocol/protocol.constant.js.map +1 -0
  27. package/dist/runtime/descriptor/element-descriptor-extractor.d.ts +38 -0
  28. package/dist/runtime/descriptor/element-descriptor-extractor.js +190 -0
  29. package/dist/runtime/descriptor/element-descriptor-extractor.js.map +1 -0
  30. package/dist/runtime/designer-runtime.d.ts +85 -0
  31. package/dist/runtime/designer-runtime.js +321 -0
  32. package/dist/runtime/designer-runtime.js.map +1 -0
  33. package/dist/runtime/guest-messenger.d.ts +37 -0
  34. package/dist/runtime/guest-messenger.js +41 -0
  35. package/dist/runtime/guest-messenger.js.map +1 -0
  36. package/dist/runtime/handshake-gate.d.ts +35 -0
  37. package/dist/runtime/handshake-gate.js +81 -0
  38. package/dist/runtime/handshake-gate.js.map +1 -0
  39. package/dist/runtime/highlight/highlight-overlay.d.ts +25 -0
  40. package/dist/runtime/highlight/highlight-overlay.js +80 -0
  41. package/dist/runtime/highlight/highlight-overlay.js.map +1 -0
  42. package/dist/runtime/region/dom-hit-tester.d.ts +28 -0
  43. package/dist/runtime/region/dom-hit-tester.js +45 -0
  44. package/dist/runtime/region/dom-hit-tester.js.map +1 -0
  45. package/dist/runtime/region/element-filter.d.ts +60 -0
  46. package/dist/runtime/region/element-filter.js +146 -0
  47. package/dist/runtime/region/element-filter.js.map +1 -0
  48. package/dist/runtime/region/region-sampler.d.ts +41 -0
  49. package/dist/runtime/region/region-sampler.js +100 -0
  50. package/dist/runtime/region/region-sampler.js.map +1 -0
  51. package/dist/runtime/region/spray-region-resolver.d.ts +53 -0
  52. package/dist/runtime/region/spray-region-resolver.js +113 -0
  53. package/dist/runtime/region/spray-region-resolver.js.map +1 -0
  54. package/dist/util/geometry.util.d.ts +29 -0
  55. package/dist/util/geometry.util.js +68 -0
  56. package/dist/util/geometry.util.js.map +1 -0
  57. package/package.json +49 -0
@@ -0,0 +1,190 @@
1
+ import { SOURCE_ATTRIBUTE } from '../../protocol/protocol.constant.js';
2
+ /** How many ancestors may answer for an unstamped element's source. */
3
+ const SOURCE_ANCESTOR_HOPS = 3;
4
+ /** Maximum DOM-path length before the middle is elided. */
5
+ const DOM_PATH_DEPTH_CAP = 14;
6
+ /** Leading segments kept when a DOM path is elided. */
7
+ const DOM_PATH_HEAD_SEGMENTS = 6;
8
+ /** Trailing segments kept when a DOM path is elided. */
9
+ const DOM_PATH_TAIL_SEGMENTS = 7;
10
+ /**
11
+ * Placeholder segment marking elided middle segments of a too-deep DOM
12
+ * path: `{ tag: '…', nthOfType: 0 }`. `nthOfType` 0 is unreachable for real
13
+ * segments (they are 1-based), so consumers can detect the elision.
14
+ */
15
+ const DOM_PATH_ELISION_SEGMENT = { tag: '…', nthOfType: 0 };
16
+ /** Maximum text length carried on a descriptor before truncation. */
17
+ const TEXT_LENGTH_CAP = 120;
18
+ /** Maximum number of classes carried on a descriptor. */
19
+ const CLASS_LIST_CAP = 10;
20
+ /** Attributes worth carrying across the wire for element identification. */
21
+ const ATTRIBUTE_WHITELIST = [
22
+ 'href',
23
+ 'src',
24
+ 'alt',
25
+ 'type',
26
+ 'name',
27
+ 'placeholder',
28
+ 'aria-label',
29
+ 'data-testid',
30
+ ];
31
+ /** Implicit ARIA roles for tags whose role does not depend on attributes. */
32
+ const IMPLICIT_ROLES = new Map([
33
+ ['button', 'button'],
34
+ ['textarea', 'textbox'],
35
+ ['select', 'combobox'],
36
+ ['img', 'img'],
37
+ ['nav', 'navigation'],
38
+ ['main', 'main'],
39
+ ['header', 'banner'],
40
+ ['footer', 'contentinfo'],
41
+ ['h1', 'heading'],
42
+ ['h2', 'heading'],
43
+ ['h3', 'heading'],
44
+ ['h4', 'heading'],
45
+ ['h5', 'heading'],
46
+ ['h6', 'heading'],
47
+ ['ul', 'list'],
48
+ ['ol', 'list'],
49
+ ['li', 'listitem'],
50
+ ]);
51
+ /**
52
+ * Projects a resolved DOM element into the wire {@link ElementDescriptor} —
53
+ * everything the host (and ultimately the AI agent) needs to identify the
54
+ * element in the storefront source tree without access to the live DOM.
55
+ */
56
+ export class ElementDescriptorExtractor {
57
+ win;
58
+ constructor(win) {
59
+ this.win = win;
60
+ }
61
+ extract(element, refId, coverage) {
62
+ return {
63
+ refId,
64
+ tagName: element.tagName.toLowerCase(),
65
+ id: element.id.length > 0 ? element.id : null,
66
+ classList: Array.from(element.classList).slice(0, CLASS_LIST_CAP),
67
+ domPath: this.buildDomPath(element),
68
+ source: this.resolveSource(element),
69
+ text: this.extractText(element),
70
+ role: this.resolveRole(element),
71
+ attributes: this.collectAttributes(element),
72
+ bounds: this.toRect(element.getBoundingClientRect()),
73
+ coverage,
74
+ childCount: element.childElementCount,
75
+ };
76
+ }
77
+ /**
78
+ * Finds the nearest `data-fc-source` stamp on the element or up to three
79
+ * ancestors (components often render a stamped wrapper around unstamped
80
+ * children). The first stamp found is authoritative: a malformed stamp
81
+ * yields null instead of climbing further, which would misattribute the
82
+ * element to an outer component.
83
+ */
84
+ resolveSource(element) {
85
+ let current = element;
86
+ for (let hop = 0; hop <= SOURCE_ANCESTOR_HOPS && current !== null; hop++) {
87
+ const raw = current.getAttribute(SOURCE_ATTRIBUTE);
88
+ if (raw !== null)
89
+ return this.parseSource(raw);
90
+ current = current.parentElement;
91
+ }
92
+ return null;
93
+ }
94
+ /**
95
+ * Parses `<file>:<line>:<col>:<ComponentName>` by splitting from the
96
+ * right — the trailing three segments are component, column and line; the
97
+ * rest re-joins as the file path, so colon-bearing paths survive.
98
+ */
99
+ parseSource(raw) {
100
+ const parts = raw.split(':');
101
+ if (parts.length < 4)
102
+ return null;
103
+ const componentName = parts[parts.length - 1];
104
+ const column = this.parsePosition(parts[parts.length - 2]);
105
+ const line = this.parsePosition(parts[parts.length - 3]);
106
+ const file = parts.slice(0, parts.length - 3).join(':');
107
+ if (line === null || column === null || file.length === 0)
108
+ return null;
109
+ return {
110
+ file,
111
+ line,
112
+ column,
113
+ componentName: componentName.length > 0 ? componentName : null,
114
+ };
115
+ }
116
+ parsePosition(segment) {
117
+ if (!/^\d+$/.test(segment))
118
+ return null;
119
+ const value = Number(segment);
120
+ return Number.isSafeInteger(value) ? value : null;
121
+ }
122
+ /**
123
+ * Body-rooted `tag:nth-of-type` path. `nthOfType` counts same-tag element
124
+ * siblings, 1-based. Paths deeper than 14 segments keep the first 6 and
125
+ * last 7 with {@link DOM_PATH_ELISION_SEGMENT} marking the elided middle.
126
+ */
127
+ buildDomPath(element) {
128
+ const segments = [];
129
+ let current = element;
130
+ while (current !== null && current !== this.win.document.documentElement) {
131
+ segments.unshift({ tag: current.tagName.toLowerCase(), nthOfType: this.nthOfType(current) });
132
+ if (current === this.win.document.body)
133
+ break;
134
+ current = current.parentElement;
135
+ }
136
+ if (segments.length <= DOM_PATH_DEPTH_CAP)
137
+ return segments;
138
+ return [
139
+ ...segments.slice(0, DOM_PATH_HEAD_SEGMENTS),
140
+ DOM_PATH_ELISION_SEGMENT,
141
+ ...segments.slice(segments.length - DOM_PATH_TAIL_SEGMENTS),
142
+ ];
143
+ }
144
+ nthOfType(element) {
145
+ let index = 1;
146
+ let sibling = element.previousElementSibling;
147
+ while (sibling !== null) {
148
+ if (sibling.tagName === element.tagName)
149
+ index++;
150
+ sibling = sibling.previousElementSibling;
151
+ }
152
+ return index;
153
+ }
154
+ extractText(element) {
155
+ const collapsed = element.textContent.replace(/\s+/g, ' ').trim();
156
+ if (collapsed.length === 0)
157
+ return null;
158
+ if (collapsed.length <= TEXT_LENGTH_CAP)
159
+ return collapsed;
160
+ return `${collapsed.slice(0, TEXT_LENGTH_CAP)}…`;
161
+ }
162
+ resolveRole(element) {
163
+ const explicit = element.getAttribute('role');
164
+ if (explicit !== null && explicit.length > 0)
165
+ return explicit;
166
+ const tag = element.tagName.toLowerCase();
167
+ if (tag === 'a')
168
+ return element.hasAttribute('href') ? 'link' : null;
169
+ if (tag === 'input')
170
+ return this.inputRole(element);
171
+ return IMPLICIT_ROLES.get(tag) ?? null;
172
+ }
173
+ inputRole(element) {
174
+ const type = element.getAttribute('type');
175
+ return type === 'submit' || type === 'button' ? 'button' : 'textbox';
176
+ }
177
+ collectAttributes(element) {
178
+ const attributes = {};
179
+ for (const name of ATTRIBUTE_WHITELIST) {
180
+ const value = element.getAttribute(name);
181
+ if (value !== null)
182
+ attributes[name] = value;
183
+ }
184
+ return attributes;
185
+ }
186
+ toRect(rect) {
187
+ return { x: rect.x, y: rect.y, width: rect.width, height: rect.height };
188
+ }
189
+ }
190
+ //# sourceMappingURL=element-descriptor-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"element-descriptor-extractor.js","sourceRoot":"","sources":["../../../src/runtime/descriptor/element-descriptor-extractor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ import type { MessageCodec } from '../protocol/message-codec.js';
2
+ import type { GuestMessenger } from './guest-messenger.js';
3
+ import type { HandshakeGate } from './handshake-gate.js';
4
+ import type { HighlightOverlay } from './highlight/highlight-overlay.js';
5
+ import type { SprayRegionResolver } from './region/spray-region-resolver.js';
6
+ /**
7
+ * The guest endpoint of the visual-editor wire protocol. Owns the runtime
8
+ * state machine and routes every inbound window message: foreign traffic is
9
+ * ignored silently, namespaced-but-malformed traffic from the trusted host
10
+ * is answered with INVALID_MESSAGE, and valid host messages dispatch to the
11
+ * region/highlight subsystems. Trust is never implicit — apart from HELLO
12
+ * (validated by the {@link HandshakeGate}), every message must come from the
13
+ * parent window at the pinned origin while the runtime is handshaken.
14
+ */
15
+ export declare class DesignerRuntime {
16
+ private readonly win;
17
+ private readonly codec;
18
+ private readonly gate;
19
+ private readonly messenger;
20
+ private readonly resolver;
21
+ private readonly overlay;
22
+ private state;
23
+ private messageListener;
24
+ private armed;
25
+ private scrollFrame;
26
+ private resizeFrame;
27
+ constructor(win: Window, codec: MessageCodec, gate: HandshakeGate, messenger: GuestMessenger, resolver: SprayRegionResolver, overlay: HighlightOverlay);
28
+ /**
29
+ * Registers exactly one window `message` listener and posts the READY
30
+ * beacon so an already-listening host can start the handshake. Calling
31
+ * install on an installed runtime is a no-op.
32
+ */
33
+ install(): void;
34
+ /**
35
+ * Full idempotent teardown: emitters disarmed, overlay removed, ref
36
+ * stamps stripped, the message listener removed and the state machine
37
+ * reset to dormant.
38
+ */
39
+ dispose(): void;
40
+ /**
41
+ * Dispatch boundary. The runtime lives inside arbitrary tenant pages with
42
+ * no error transport of its own, so this is the one try/catch: a throw
43
+ * anywhere in dispatch becomes a protocol ERROR(INTERNAL) to the pinned
44
+ * host (a silent no-op pre-handshake) instead of an unhandled exception
45
+ * in the storefront's console.
46
+ */
47
+ private onMessage;
48
+ private routeMessage;
49
+ /**
50
+ * Namespaced traffic that failed validation is only answered when it
51
+ * provably came from the handshaken host — anything else stays silent so
52
+ * the runtime leaks nothing to arbitrary message senders.
53
+ */
54
+ private handleUnparseable;
55
+ private handleHello;
56
+ private dispatch;
57
+ private handleActivate;
58
+ private handleDeactivate;
59
+ private handlePing;
60
+ private handleRegionSelect;
61
+ /**
62
+ * Stale refs (elements unmounted since their REGION_SELECT) are skipped;
63
+ * only a request where every ref is stale is answered with UNKNOWN_REF —
64
+ * partial selections still highlight what is left.
65
+ */
66
+ private handleHighlightSet;
67
+ private handleElementBoundsQuery;
68
+ private armEmitters;
69
+ private disarmEmitters;
70
+ /** rAF throttle: at most one pending frame per emitter channel. */
71
+ private scheduleFrame;
72
+ private cancelFrames;
73
+ private emitScroll;
74
+ private emitResize;
75
+ private emitNavigated;
76
+ private postError;
77
+ private teardownActivation;
78
+ private stripRefStamps;
79
+ private findByRef;
80
+ private isTrustedHostEvent;
81
+ private extractRequestId;
82
+ private getViewport;
83
+ private getScroll;
84
+ private toRect;
85
+ }
@@ -0,0 +1,321 @@
1
+ import { REF_ATTRIBUTE, SOURCE_ATTRIBUTE } from '../protocol/protocol.constant.js';
2
+ /**
3
+ * The guest endpoint of the visual-editor wire protocol. Owns the runtime
4
+ * state machine and routes every inbound window message: foreign traffic is
5
+ * ignored silently, namespaced-but-malformed traffic from the trusted host
6
+ * is answered with INVALID_MESSAGE, and valid host messages dispatch to the
7
+ * region/highlight subsystems. Trust is never implicit — apart from HELLO
8
+ * (validated by the {@link HandshakeGate}), every message must come from the
9
+ * parent window at the pinned origin while the runtime is handshaken.
10
+ */
11
+ export class DesignerRuntime {
12
+ win;
13
+ codec;
14
+ gate;
15
+ messenger;
16
+ resolver;
17
+ overlay;
18
+ state = 'dormant';
19
+ messageListener = null;
20
+ armed = null;
21
+ scrollFrame = null;
22
+ resizeFrame = null;
23
+ constructor(win, codec, gate, messenger, resolver, overlay) {
24
+ this.win = win;
25
+ this.codec = codec;
26
+ this.gate = gate;
27
+ this.messenger = messenger;
28
+ this.resolver = resolver;
29
+ this.overlay = overlay;
30
+ }
31
+ /**
32
+ * Registers exactly one window `message` listener and posts the READY
33
+ * beacon so an already-listening host can start the handshake. Calling
34
+ * install on an installed runtime is a no-op.
35
+ */
36
+ install() {
37
+ if (this.messageListener !== null)
38
+ return;
39
+ this.messageListener = (event) => {
40
+ this.onMessage(event);
41
+ };
42
+ this.win.addEventListener('message', this.messageListener);
43
+ this.messenger.postReady();
44
+ }
45
+ /**
46
+ * Full idempotent teardown: emitters disarmed, overlay removed, ref
47
+ * stamps stripped, the message listener removed and the state machine
48
+ * reset to dormant.
49
+ */
50
+ dispose() {
51
+ this.teardownActivation();
52
+ if (this.messageListener !== null) {
53
+ this.win.removeEventListener('message', this.messageListener);
54
+ this.messageListener = null;
55
+ }
56
+ this.state = 'dormant';
57
+ }
58
+ /**
59
+ * Dispatch boundary. The runtime lives inside arbitrary tenant pages with
60
+ * no error transport of its own, so this is the one try/catch: a throw
61
+ * anywhere in dispatch becomes a protocol ERROR(INTERNAL) to the pinned
62
+ * host (a silent no-op pre-handshake) instead of an unhandled exception
63
+ * in the storefront's console.
64
+ */
65
+ onMessage(event) {
66
+ try {
67
+ this.routeMessage(event);
68
+ }
69
+ catch (error) {
70
+ this.messenger.post({
71
+ type: 'ERROR',
72
+ code: 'INTERNAL',
73
+ requestId: this.extractRequestId(event.data),
74
+ detail: error instanceof Error ? error.message : null,
75
+ });
76
+ }
77
+ }
78
+ routeMessage(event) {
79
+ const message = this.codec.parseHostMessage(event.data);
80
+ if (message === null) {
81
+ this.handleUnparseable(event);
82
+ return;
83
+ }
84
+ if (message.type === 'HELLO') {
85
+ this.handleHello(event, message);
86
+ return;
87
+ }
88
+ if (this.state === 'dormant' || !this.isTrustedHostEvent(event))
89
+ return;
90
+ this.dispatch(message);
91
+ }
92
+ /**
93
+ * Namespaced traffic that failed validation is only answered when it
94
+ * provably came from the handshaken host — anything else stays silent so
95
+ * the runtime leaks nothing to arbitrary message senders.
96
+ */
97
+ handleUnparseable(event) {
98
+ if (!this.codec.hasProtocolNamespace(event.data))
99
+ return;
100
+ if (this.state === 'dormant' || !this.isTrustedHostEvent(event))
101
+ return;
102
+ this.messenger.post({
103
+ type: 'ERROR',
104
+ code: 'INVALID_MESSAGE',
105
+ requestId: this.extractRequestId(event.data),
106
+ detail: 'message failed protocol validation',
107
+ });
108
+ }
109
+ handleHello(event, message) {
110
+ if (!this.gate.acceptHello(event, message))
111
+ return;
112
+ const pinned = this.gate.getPinnedOrigin();
113
+ if (pinned === null)
114
+ return;
115
+ this.messenger.pinOrigin(pinned);
116
+ if (this.state === 'dormant')
117
+ this.state = 'handshaken';
118
+ this.messenger.post({
119
+ type: 'HELLO_ACK',
120
+ capabilities: {
121
+ stamping: this.win.document.querySelector(`[${SOURCE_ATTRIBUTE}]`) !== null,
122
+ highlight: true,
123
+ },
124
+ url: this.win.location.href,
125
+ viewport: this.getViewport(),
126
+ });
127
+ }
128
+ dispatch(message) {
129
+ switch (message.type) {
130
+ case 'ACTIVATE':
131
+ this.handleActivate();
132
+ return;
133
+ case 'DEACTIVATE':
134
+ this.handleDeactivate();
135
+ return;
136
+ case 'PING':
137
+ this.handlePing();
138
+ return;
139
+ case 'REGION_SELECT':
140
+ this.handleRegionSelect(message);
141
+ return;
142
+ case 'HIGHLIGHT_SET':
143
+ this.handleHighlightSet(message);
144
+ return;
145
+ case 'HIGHLIGHT_CLEAR':
146
+ this.overlay.clear();
147
+ return;
148
+ case 'ELEMENT_BOUNDS_QUERY':
149
+ this.handleElementBoundsQuery(message);
150
+ return;
151
+ }
152
+ }
153
+ handleActivate() {
154
+ if (this.state !== 'active') {
155
+ this.armEmitters();
156
+ this.state = 'active';
157
+ }
158
+ this.messenger.post({ type: 'ACTIVATED' });
159
+ }
160
+ handleDeactivate() {
161
+ this.teardownActivation();
162
+ this.state = 'handshaken';
163
+ this.messenger.post({ type: 'DEACTIVATED' });
164
+ }
165
+ handlePing() {
166
+ this.messenger.post({
167
+ type: 'PONG',
168
+ url: this.win.location.href,
169
+ scroll: this.getScroll(),
170
+ });
171
+ }
172
+ handleRegionSelect(message) {
173
+ if (this.state !== 'active') {
174
+ this.postError('NOT_ACTIVE', message.requestId);
175
+ return;
176
+ }
177
+ const resolution = this.resolver.resolve(message.stroke, message.radius, message.maxElements);
178
+ if (resolution.kind === 'too-large') {
179
+ this.postError('REGION_TOO_LARGE', message.requestId);
180
+ return;
181
+ }
182
+ this.messenger.post({
183
+ type: 'REGION_RESOLVED',
184
+ requestId: message.requestId,
185
+ elements: resolution.elements,
186
+ regionBounds: resolution.regionBounds,
187
+ truncated: resolution.truncated,
188
+ });
189
+ }
190
+ /**
191
+ * Stale refs (elements unmounted since their REGION_SELECT) are skipped;
192
+ * only a request where every ref is stale is answered with UNKNOWN_REF —
193
+ * partial selections still highlight what is left.
194
+ */
195
+ handleHighlightSet(message) {
196
+ const found = [];
197
+ for (const refId of message.refIds) {
198
+ const element = this.findByRef(refId);
199
+ if (element !== null)
200
+ found.push(element);
201
+ }
202
+ if (found.length === 0 && message.refIds.length > 0) {
203
+ this.postError('UNKNOWN_REF', null);
204
+ return;
205
+ }
206
+ this.overlay.show(found);
207
+ }
208
+ handleElementBoundsQuery(message) {
209
+ const entries = message.refIds.map((refId) => {
210
+ const element = this.findByRef(refId);
211
+ return {
212
+ refId,
213
+ bounds: element === null ? null : this.toRect(element.getBoundingClientRect()),
214
+ };
215
+ });
216
+ this.messenger.post({ type: 'ELEMENT_BOUNDS', requestId: message.requestId, entries });
217
+ }
218
+ armEmitters() {
219
+ if (this.armed !== null)
220
+ return;
221
+ this.armed = {
222
+ scroll: () => {
223
+ this.scheduleFrame('scrollFrame', () => {
224
+ this.emitScroll();
225
+ });
226
+ },
227
+ resize: () => {
228
+ this.scheduleFrame('resizeFrame', () => {
229
+ this.emitResize();
230
+ });
231
+ },
232
+ popstate: () => {
233
+ this.emitNavigated();
234
+ },
235
+ hashchange: () => {
236
+ this.emitNavigated();
237
+ },
238
+ };
239
+ this.win.addEventListener('scroll', this.armed.scroll, { passive: true });
240
+ this.win.addEventListener('resize', this.armed.resize);
241
+ this.win.addEventListener('popstate', this.armed.popstate);
242
+ this.win.addEventListener('hashchange', this.armed.hashchange);
243
+ }
244
+ disarmEmitters() {
245
+ if (this.armed === null)
246
+ return;
247
+ this.win.removeEventListener('scroll', this.armed.scroll);
248
+ this.win.removeEventListener('resize', this.armed.resize);
249
+ this.win.removeEventListener('popstate', this.armed.popstate);
250
+ this.win.removeEventListener('hashchange', this.armed.hashchange);
251
+ this.armed = null;
252
+ this.cancelFrames();
253
+ }
254
+ /** rAF throttle: at most one pending frame per emitter channel. */
255
+ scheduleFrame(channel, emit) {
256
+ if (this[channel] !== null)
257
+ return;
258
+ this[channel] = this.win.requestAnimationFrame(() => {
259
+ this[channel] = null;
260
+ this.overlay.refresh();
261
+ emit();
262
+ });
263
+ }
264
+ cancelFrames() {
265
+ if (this.scrollFrame !== null) {
266
+ this.win.cancelAnimationFrame(this.scrollFrame);
267
+ this.scrollFrame = null;
268
+ }
269
+ if (this.resizeFrame !== null) {
270
+ this.win.cancelAnimationFrame(this.resizeFrame);
271
+ this.resizeFrame = null;
272
+ }
273
+ }
274
+ emitScroll() {
275
+ this.messenger.post({ type: 'SCROLL', scroll: this.getScroll() });
276
+ }
277
+ emitResize() {
278
+ this.messenger.post({ type: 'RESIZE', viewport: this.getViewport() });
279
+ }
280
+ emitNavigated() {
281
+ this.messenger.post({ type: 'NAVIGATED', url: this.win.location.href });
282
+ }
283
+ postError(code, requestId) {
284
+ this.messenger.post({ type: 'ERROR', code, requestId, detail: null });
285
+ }
286
+ teardownActivation() {
287
+ this.overlay.dispose();
288
+ this.stripRefStamps();
289
+ this.disarmEmitters();
290
+ }
291
+ stripRefStamps() {
292
+ for (const element of this.win.document.querySelectorAll(`[${REF_ATTRIBUTE}]`)) {
293
+ element.removeAttribute(REF_ATTRIBUTE);
294
+ }
295
+ }
296
+ findByRef(refId) {
297
+ const escaped = refId.replace(/[\\"]/g, '\\$&');
298
+ return this.win.document.querySelector(`[${REF_ATTRIBUTE}="${escaped}"]`);
299
+ }
300
+ isTrustedHostEvent(event) {
301
+ const pinned = this.gate.getPinnedOrigin();
302
+ return pinned !== null && event.origin === pinned && event.source === this.win.parent;
303
+ }
304
+ extractRequestId(data) {
305
+ if (typeof data !== 'object' || data === null)
306
+ return null;
307
+ if (!('requestId' in data))
308
+ return null;
309
+ return typeof data.requestId === 'string' ? data.requestId : null;
310
+ }
311
+ getViewport() {
312
+ return { width: this.win.innerWidth, height: this.win.innerHeight };
313
+ }
314
+ getScroll() {
315
+ return { x: this.win.scrollX, y: this.win.scrollY };
316
+ }
317
+ toRect(rect) {
318
+ return { x: rect.x, y: rect.y, width: rect.width, height: rect.height };
319
+ }
320
+ }
321
+ //# sourceMappingURL=designer-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"designer-runtime.js","sourceRoot":"","sources":["../../src/runtime/designer-runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { GuestMessage } from '../protocol/message.types.js';
2
+ /**
3
+ * A {@link GuestMessage} without the protocol envelope — the messenger stamps
4
+ * `ns` + `v` on every send so no call site can forget (or fake) them.
5
+ */
6
+ export type GuestMessageBody = {
7
+ [K in GuestMessage['type']]: Omit<Extract<GuestMessage, {
8
+ type: K;
9
+ }>, 'ns' | 'v'>;
10
+ }[GuestMessage['type']];
11
+ /**
12
+ * The guest's only postMessage exit. Every message except the boot READY
13
+ * beacon is posted with the origin pinned by the handshake — the browser
14
+ * drops the message if the embedding page navigated elsewhere, so guest data
15
+ * can never leak to a window that is no longer the dashboard.
16
+ */
17
+ export declare class GuestMessenger {
18
+ private readonly targetWindow;
19
+ private pinnedOrigin;
20
+ constructor(targetWindow: Window);
21
+ /**
22
+ * The pre-handshake boot beacon — the single message ever posted with
23
+ * targetOrigin `'*'`. It carries zero payload beyond the envelope, so an
24
+ * arbitrary embedder learns nothing it could not infer from the public
25
+ * storefront template.
26
+ */
27
+ postReady(): void;
28
+ /** Pin the host origin after a validated HELLO; later pins must match. */
29
+ pinOrigin(origin: string): void;
30
+ getPinnedOrigin(): string | null;
31
+ /**
32
+ * Post a protocol message to the pinned host origin. Before the handshake
33
+ * pinned an origin this is a silent no-op — pre-handshake the guest says
34
+ * nothing but READY.
35
+ */
36
+ post(body: GuestMessageBody): void;
37
+ }