@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,100 @@
1
+ import { distanceBetween, padBoundingBox, pointsBoundingBox, } from '../../util/geometry.util.js';
2
+ /** Hard ceiling on covered cells before the sampler coarsens the grid. */
3
+ const CELL_BUDGET = 600;
4
+ /** A region larger than this multiple of the viewport area is rejected. */
5
+ const MAX_VIEWPORT_AREA_FACTOR = 4;
6
+ /** Upper bound on the polyline walk step, in CSS pixels. */
7
+ const MAX_WALK_STEP = 16;
8
+ /**
9
+ * Pure stroke-to-grid rasterizer for spray selection. The stroke is walked
10
+ * at a fixed step and every grid cell whose center lies within the spray
11
+ * radius of a step point is marked. The grid covers the stroke's padded
12
+ * bounding box; when the marked-cell count blows the budget the cell size is
13
+ * doubled and the stroke re-rasterized, trading sampling density for a
14
+ * bounded number of elementsFromPoint calls downstream.
15
+ */
16
+ export class RegionSampler {
17
+ sample(stroke, radius, viewport) {
18
+ const padded = padBoundingBox(pointsBoundingBox(stroke), radius);
19
+ const viewportArea = viewport.width * viewport.height;
20
+ if (padded.width * padded.height > MAX_VIEWPORT_AREA_FACTOR * viewportArea) {
21
+ return { kind: 'too-large' };
22
+ }
23
+ const stepPoints = this.walkPolyline(stroke, Math.min(radius, MAX_WALK_STEP));
24
+ let cellSize = Math.max(8, radius / 2);
25
+ for (;;) {
26
+ const centers = this.rasterize(padded, cellSize, stepPoints, radius, viewport);
27
+ if (centers.length <= CELL_BUDGET)
28
+ return { kind: 'ok', cellCenters: centers, cellSize };
29
+ cellSize *= 2;
30
+ }
31
+ }
32
+ /**
33
+ * Resamples the stroke polyline at `step`-pixel intervals. Both endpoints
34
+ * of every segment are included; a single-point stroke yields that point,
35
+ * so a click-without-drag still samples around the click.
36
+ */
37
+ walkPolyline(stroke, step) {
38
+ if (stroke.length === 0)
39
+ return [];
40
+ const points = [stroke[0]];
41
+ for (let i = 1; i < stroke.length; i++) {
42
+ const from = stroke[i - 1];
43
+ const to = stroke[i];
44
+ const segments = Math.max(1, Math.ceil(distanceBetween(from, to) / step));
45
+ for (let s = 1; s <= segments; s++) {
46
+ const t = s / segments;
47
+ points.push({ x: from.x + (to.x - from.x) * t, y: from.y + (to.y - from.y) * t });
48
+ }
49
+ }
50
+ return points;
51
+ }
52
+ /**
53
+ * Marks the cells covered by the stroke. Instead of testing every grid
54
+ * cell against every step point, each step point only visits the cell
55
+ * window its radius can reach — O(steps × (radius / cellSize)²) — and the
56
+ * covered set is deduplicated through linear cell indices.
57
+ */
58
+ rasterize(box, cellSize, stepPoints, radius, viewport) {
59
+ const columns = Math.max(1, Math.ceil(box.width / cellSize));
60
+ const rows = Math.max(1, Math.ceil(box.height / cellSize));
61
+ const covered = new Set();
62
+ for (const point of stepPoints) {
63
+ const minColumn = this.clampIndex(Math.floor((point.x - radius - box.left) / cellSize), columns);
64
+ const maxColumn = this.clampIndex(Math.floor((point.x + radius - box.left) / cellSize), columns);
65
+ const minRow = this.clampIndex(Math.floor((point.y - radius - box.top) / cellSize), rows);
66
+ const maxRow = this.clampIndex(Math.floor((point.y + radius - box.top) / cellSize), rows);
67
+ for (let row = minRow; row <= maxRow; row++) {
68
+ for (let column = minColumn; column <= maxColumn; column++) {
69
+ const center = this.cellCenter(box, cellSize, column, row);
70
+ if (distanceBetween(center, point) <= radius)
71
+ covered.add(row * columns + column);
72
+ }
73
+ }
74
+ }
75
+ const centers = [];
76
+ for (const index of covered) {
77
+ const center = this.cellCenter(box, cellSize, index % columns, Math.floor(index / columns));
78
+ if (this.isInsideViewport(center, viewport))
79
+ centers.push(center);
80
+ }
81
+ return centers;
82
+ }
83
+ cellCenter(box, cellSize, column, row) {
84
+ return {
85
+ x: box.left + (column + 0.5) * cellSize,
86
+ y: box.top + (row + 0.5) * cellSize,
87
+ };
88
+ }
89
+ clampIndex(index, count) {
90
+ if (index < 0)
91
+ return 0;
92
+ if (index > count - 1)
93
+ return count - 1;
94
+ return index;
95
+ }
96
+ isInsideViewport(point, viewport) {
97
+ return point.x >= 0 && point.x <= viewport.width && point.y >= 0 && point.y <= viewport.height;
98
+ }
99
+ }
100
+ //# sourceMappingURL=region-sampler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"region-sampler.js","sourceRoot":"","sources":["../../../src/runtime/region/region-sampler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import type { ElementDescriptor, Point, Rect } from '../../protocol/element.types.js';
2
+ import type { ElementDescriptorExtractor } from '../descriptor/element-descriptor-extractor.js';
3
+ import type { HitTester } from './dom-hit-tester.js';
4
+ import type { ElementFilter } from './element-filter.js';
5
+ import type { RegionSampler } from './region-sampler.js';
6
+ /** A resolved spray region: descriptors plus the region's clamped bounds. */
7
+ export interface RegionResolutionOk {
8
+ kind: 'ok';
9
+ elements: ElementDescriptor[];
10
+ regionBounds: Rect;
11
+ truncated: boolean;
12
+ }
13
+ /** The stroke's padded bounding box exceeds the region budget. */
14
+ export interface RegionResolutionTooLarge {
15
+ kind: 'too-large';
16
+ }
17
+ export type RegionResolution = RegionResolutionOk | RegionResolutionTooLarge;
18
+ /**
19
+ * The REGION_SELECT pipeline: rasterize the stroke into cell centers, stack
20
+ * hit-test every center, keep the meaningful elements, weigh coverage,
21
+ * collapse ancestor/descendant stacks, rank, cap and stamp the survivors
22
+ * with `data-fc-ref` so later HIGHLIGHT_SET / ELEMENT_BOUNDS_QUERY calls can
23
+ * address them.
24
+ *
25
+ * Ref stamps accumulate over the activation — earlier selections keep their
26
+ * refIds valid for already-open threads — and are stripped wholesale on
27
+ * DEACTIVATE. An element re-selected by a later spray keeps its existing
28
+ * stamp, so a refId never silently changes meaning; fresh stamps come from a
29
+ * per-resolver counter and stay unique across calls.
30
+ */
31
+ export declare class SprayRegionResolver {
32
+ private readonly sampler;
33
+ private readonly hitTester;
34
+ private readonly filter;
35
+ private readonly extractor;
36
+ private readonly doc;
37
+ private refCounter;
38
+ constructor(sampler: RegionSampler, hitTester: HitTester, filter: ElementFilter, extractor: ElementDescriptorExtractor, doc: Document);
39
+ resolve(stroke: readonly Point[], radius: number, maxElements: number | undefined): RegionResolution;
40
+ /** Stack hit-test every cell center, accumulating cell indices per element. */
41
+ private collectHits;
42
+ /**
43
+ * Filters to meaningful elements and computes per-element coverage: the
44
+ * fraction of the sampled cell centers inside the element's bounds whose
45
+ * hit stack actually contained it.
46
+ */
47
+ private toCandidates;
48
+ private countCentersInside;
49
+ /** Reuses an element's existing ref stamp, or assigns the next unique one. */
50
+ private stampRef;
51
+ private getViewport;
52
+ private toRect;
53
+ }
@@ -0,0 +1,113 @@
1
+ import { REF_ATTRIBUTE } from '../../protocol/protocol.constant.js';
2
+ import { clampRectToBounds, padBoundingBox, pointsBoundingBox, } from '../../util/geometry.util.js';
3
+ /**
4
+ * The REGION_SELECT pipeline: rasterize the stroke into cell centers, stack
5
+ * hit-test every center, keep the meaningful elements, weigh coverage,
6
+ * collapse ancestor/descendant stacks, rank, cap and stamp the survivors
7
+ * with `data-fc-ref` so later HIGHLIGHT_SET / ELEMENT_BOUNDS_QUERY calls can
8
+ * address them.
9
+ *
10
+ * Ref stamps accumulate over the activation — earlier selections keep their
11
+ * refIds valid for already-open threads — and are stripped wholesale on
12
+ * DEACTIVATE. An element re-selected by a later spray keeps its existing
13
+ * stamp, so a refId never silently changes meaning; fresh stamps come from a
14
+ * per-resolver counter and stay unique across calls.
15
+ */
16
+ export class SprayRegionResolver {
17
+ sampler;
18
+ hitTester;
19
+ filter;
20
+ extractor;
21
+ doc;
22
+ refCounter = 0;
23
+ constructor(sampler, hitTester, filter, extractor, doc) {
24
+ this.sampler = sampler;
25
+ this.hitTester = hitTester;
26
+ this.filter = filter;
27
+ this.extractor = extractor;
28
+ this.doc = doc;
29
+ }
30
+ resolve(stroke, radius, maxElements) {
31
+ const viewport = this.getViewport();
32
+ const sampled = this.sampler.sample(stroke, radius, viewport);
33
+ if (sampled.kind === 'too-large')
34
+ return { kind: 'too-large' };
35
+ const hits = this.collectHits(sampled.cellCenters);
36
+ const candidates = this.toCandidates(hits, sampled.cellCenters, viewport);
37
+ const survivors = this.filter.dedupeAncestors(candidates);
38
+ const ranked = this.filter.rankAndCap(survivors, maxElements);
39
+ const elements = ranked.candidates.map((candidate) => this.extractor.extract(candidate.element, this.stampRef(candidate.element), candidate.coverage));
40
+ return {
41
+ kind: 'ok',
42
+ elements,
43
+ regionBounds: clampRectToBounds(padBoundingBox(pointsBoundingBox(stroke), radius), viewport),
44
+ truncated: ranked.truncated,
45
+ };
46
+ }
47
+ /** Stack hit-test every cell center, accumulating cell indices per element. */
48
+ collectHits(cellCenters) {
49
+ const hits = new Map();
50
+ for (let index = 0; index < cellCenters.length; index++) {
51
+ for (const element of this.hitTester.elementsAt(cellCenters[index])) {
52
+ const cells = hits.get(element);
53
+ if (cells === undefined) {
54
+ hits.set(element, new Set([index]));
55
+ continue;
56
+ }
57
+ cells.add(index);
58
+ }
59
+ }
60
+ return hits;
61
+ }
62
+ /**
63
+ * Filters to meaningful elements and computes per-element coverage: the
64
+ * fraction of the sampled cell centers inside the element's bounds whose
65
+ * hit stack actually contained it.
66
+ */
67
+ toCandidates(hits, cellCenters, viewport) {
68
+ const candidates = [];
69
+ for (const [element, hitCells] of hits) {
70
+ if (!this.filter.isMeaningful(element, viewport))
71
+ continue;
72
+ const bounds = this.toRect(element.getBoundingClientRect());
73
+ const centersInside = this.countCentersInside(cellCenters, bounds);
74
+ candidates.push({
75
+ element,
76
+ bounds,
77
+ hitCells,
78
+ coverage: hitCells.size / Math.max(1, centersInside),
79
+ });
80
+ }
81
+ return candidates;
82
+ }
83
+ countCentersInside(cellCenters, bounds) {
84
+ let count = 0;
85
+ for (const center of cellCenters) {
86
+ if (center.x >= bounds.x &&
87
+ center.x <= bounds.x + bounds.width &&
88
+ center.y >= bounds.y &&
89
+ center.y <= bounds.y + bounds.height) {
90
+ count++;
91
+ }
92
+ }
93
+ return count;
94
+ }
95
+ /** Reuses an element's existing ref stamp, or assigns the next unique one. */
96
+ stampRef(element) {
97
+ const existing = element.getAttribute(REF_ATTRIBUTE);
98
+ if (existing !== null && existing.length > 0)
99
+ return existing;
100
+ this.refCounter++;
101
+ const refId = `fcd-${String(this.refCounter)}`;
102
+ element.setAttribute(REF_ATTRIBUTE, refId);
103
+ return refId;
104
+ }
105
+ getViewport() {
106
+ const root = this.doc.documentElement;
107
+ return { width: root.clientWidth, height: root.clientHeight };
108
+ }
109
+ toRect(rect) {
110
+ return { x: rect.x, y: rect.y, width: rect.width, height: rect.height };
111
+ }
112
+ }
113
+ //# sourceMappingURL=spray-region-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spray-region-resolver.js","sourceRoot":"","sources":["../../../src/runtime/region/spray-region-resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { Point, Rect, Viewport } from '../protocol/element.types.js';
2
+ /**
3
+ * An edge-addressed bounding box. Space-agnostic — works in overlay,
4
+ * viewport or world coordinates as long as all inputs share one space.
5
+ */
6
+ export interface BoundingBox {
7
+ left: number;
8
+ top: number;
9
+ right: number;
10
+ bottom: number;
11
+ width: number;
12
+ height: number;
13
+ }
14
+ /** Bounding box of a list of points in the same coordinate space. */
15
+ export declare function pointsBoundingBox(points: readonly Point[]): BoundingBox;
16
+ /**
17
+ * Pads a bounding box by `padding` pixels on each side and, when a
18
+ * `minWidth` / `minHeight` is provided, symmetrically widens the box so it
19
+ * is at least that large.
20
+ */
21
+ export declare function padBoundingBox(box: BoundingBox, padding: number, minWidth?: number, minHeight?: number): BoundingBox;
22
+ /** Pythagoras distance between two points. */
23
+ export declare function distanceBetween(a: Point, b: Point): number;
24
+ /**
25
+ * Clamps a bounding box to `bounds` (origin 0,0) and returns an integer
26
+ * `Rect` that is at least 1×1 — the shape handed to consumers that cannot
27
+ * deal with degenerate rectangles.
28
+ */
29
+ export declare function clampRectToBounds(box: BoundingBox, bounds: Viewport): Rect;
@@ -0,0 +1,68 @@
1
+ /** Bounding box of a list of points in the same coordinate space. */
2
+ export function pointsBoundingBox(points) {
3
+ if (points.length === 0) {
4
+ return { left: 0, top: 0, right: 0, bottom: 0, width: 0, height: 0 };
5
+ }
6
+ let left = points[0].x;
7
+ let right = points[0].x;
8
+ let top = points[0].y;
9
+ let bottom = points[0].y;
10
+ for (let i = 1; i < points.length; i++) {
11
+ const point = points[i];
12
+ if (point.x < left)
13
+ left = point.x;
14
+ if (point.x > right)
15
+ right = point.x;
16
+ if (point.y < top)
17
+ top = point.y;
18
+ if (point.y > bottom)
19
+ bottom = point.y;
20
+ }
21
+ return { left, top, right, bottom, width: right - left, height: bottom - top };
22
+ }
23
+ /**
24
+ * Pads a bounding box by `padding` pixels on each side and, when a
25
+ * `minWidth` / `minHeight` is provided, symmetrically widens the box so it
26
+ * is at least that large.
27
+ */
28
+ export function padBoundingBox(box, padding, minWidth = 0, minHeight = 0) {
29
+ let left = box.left - padding;
30
+ let right = box.right + padding;
31
+ let top = box.top - padding;
32
+ let bottom = box.bottom + padding;
33
+ const widen = minWidth - (right - left);
34
+ if (widen > 0) {
35
+ left -= widen / 2;
36
+ right += widen / 2;
37
+ }
38
+ const heighten = minHeight - (bottom - top);
39
+ if (heighten > 0) {
40
+ top -= heighten / 2;
41
+ bottom += heighten / 2;
42
+ }
43
+ return { left, top, right, bottom, width: right - left, height: bottom - top };
44
+ }
45
+ /** Pythagoras distance between two points. */
46
+ export function distanceBetween(a, b) {
47
+ const dx = a.x - b.x;
48
+ const dy = a.y - b.y;
49
+ return Math.sqrt(dx * dx + dy * dy);
50
+ }
51
+ /**
52
+ * Clamps a bounding box to `bounds` (origin 0,0) and returns an integer
53
+ * `Rect` that is at least 1×1 — the shape handed to consumers that cannot
54
+ * deal with degenerate rectangles.
55
+ */
56
+ export function clampRectToBounds(box, bounds) {
57
+ const x = Math.max(0, Math.floor(box.left));
58
+ const y = Math.max(0, Math.floor(box.top));
59
+ const right = Math.min(bounds.width, Math.ceil(box.right));
60
+ const bottom = Math.min(bounds.height, Math.ceil(box.bottom));
61
+ return {
62
+ x,
63
+ y,
64
+ width: Math.max(1, right - x),
65
+ height: Math.max(1, bottom - y),
66
+ };
67
+ }
68
+ //# sourceMappingURL=geometry.util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geometry.util.js","sourceRoot":"","sources":["../../src/util/geometry.util.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@forgecart/designer-runtime",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "description": "ForgeCart visual-editor guest runtime for tenant storefronts: dormant iframe protocol endpoint, spray-region element resolution, and the Turbopack data-fc-source stamping loader",
6
+ "sideEffects": false,
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "./protocol": {
16
+ "types": "./dist/protocol/index.d.ts",
17
+ "import": "./dist/protocol/index.js",
18
+ "default": "./dist/protocol/index.js"
19
+ },
20
+ "./turbo-loader": {
21
+ "types": "./dist/loader-cjs/turbo-loader.d.ts",
22
+ "require": "./dist/loader-cjs/turbo-loader.js",
23
+ "default": "./dist/loader-cjs/turbo-loader.js"
24
+ }
25
+ },
26
+ "files": [
27
+ "dist"
28
+ ],
29
+ "dependencies": {
30
+ "@babel/parser": "^7.29.0",
31
+ "magic-string": "^0.30.21"
32
+ },
33
+ "engines": {
34
+ "node": ">=18.0.0"
35
+ },
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "keywords": [
40
+ "forgecart",
41
+ "visual-editor",
42
+ "designer",
43
+ "iframe",
44
+ "turbopack",
45
+ "loader"
46
+ ],
47
+ "author": "ForgeCart",
48
+ "license": "MIT"
49
+ }