@comty.io/core 0.1.9 → 0.1.10
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 +28 -1
- package/comty-sdk.js +3866 -1638
- package/package.json +3 -2
- package/src/anchors.js +168 -413
- package/src/browser.js +3306 -1189
- package/src/comments.js +6 -6
- package/src/dev.mjs +317 -112
- package/src/inspect-markup.js +1 -1
- package/src/measurements.js +5 -4
- package/src/resilient-anchor.js +333 -0
- package/src/resilient-anchor.ts +551 -0
- package/src/style.js +60 -33
- package/src/vite.mjs +123 -38
package/src/style.js
CHANGED
|
@@ -1,10 +1,47 @@
|
|
|
1
|
-
export function getComtyStyle() {
|
|
1
|
+
export function getComtyStyle(scope = "ui") {
|
|
2
2
|
const toolbarSurface = "#2b2d2f";
|
|
3
3
|
const toolbarMuted = "#b8babb";
|
|
4
4
|
const commentCursor = `<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 40 40"><path d="M20 2C30 2 38 10 38 20S30 38 20 38H3V28C2 25 2 23 2 20 2 10 10 2 20 2Z" fill="white" stroke="#d6dbe2"/><circle cx="20" cy="20" r="14" fill="#e6e6e6"/><path d="M20 14v12m-6-6h12" fill="none" stroke="#404040" stroke-width="2.5" stroke-linecap="round"/></svg>`;
|
|
5
5
|
const typographyCursor = `<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><rect x="8" y="8" width="23" height="23" rx="7" fill="${toolbarSurface}" stroke="${toolbarMuted}" stroke-width=".75"/><path d="m14 25 5.5-12L25 25m-8.5-4h6M13 25h4m5 0h4" fill="none" stroke="${toolbarMuted}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="m2 2 2 15 4-5 6-3Z" fill="${toolbarSurface}" stroke="${toolbarMuted}" stroke-width="1.5" stroke-linejoin="round"/></svg>`;
|
|
6
|
+
if (scope === "page") return `
|
|
7
|
+
html.comty-comment-placement,
|
|
8
|
+
html.comty-comment-placement body,
|
|
9
|
+
html.comty-comment-placement body *:not(#comty-root):not(#comty-root *) {
|
|
10
|
+
cursor: url("data:image/svg+xml,${encodeURIComponent(commentCursor)}") 16 16, crosshair !important;
|
|
11
|
+
}
|
|
12
|
+
html.comty-measure-vertical, html.comty-measure-vertical body *:not(#comty-root):not(#comty-root *) { cursor: ns-resize !important; }
|
|
13
|
+
html.comty-measure-horizontal, html.comty-measure-horizontal body *:not(#comty-root):not(#comty-root *) { cursor: ew-resize !important; }
|
|
14
|
+
html[data-comty-property-picking="color"], html[data-comty-property-picking="color"] body, html[data-comty-property-picking="color"] body :not(#comty-root):not(#comty-root *) { cursor: none !important; }
|
|
15
|
+
html[data-comty-property-picking="font"] body :not(#comty-root):not(#comty-root *) { cursor: url("data:image/svg+xml,${encodeURIComponent(typographyCursor)}") 2 2, default !important; }
|
|
16
|
+
`;
|
|
17
|
+
// Source dimensions use a 16px rem scale; emitted CSS must never use the client root.
|
|
6
18
|
return `
|
|
7
|
-
|
|
19
|
+
/* Important declarations inside the shadow tree protect the host itself,
|
|
20
|
+
including against client !important resets. Top-layer positioning also
|
|
21
|
+
escapes transformed/clipped ancestors. */
|
|
22
|
+
:host {
|
|
23
|
+
all: initial !important;
|
|
24
|
+
position: fixed !important;
|
|
25
|
+
inset: 0 !important;
|
|
26
|
+
display: block !important;
|
|
27
|
+
width: 100% !important;
|
|
28
|
+
height: 100% !important;
|
|
29
|
+
pointer-events: none !important;
|
|
30
|
+
z-index: 2147483647 !important;
|
|
31
|
+
direction: ltr !important;
|
|
32
|
+
unicode-bidi: normal !important;
|
|
33
|
+
}
|
|
34
|
+
:host::before, :host::after { content: none !important; }
|
|
35
|
+
:host::backdrop { all: initial !important; background: transparent !important; pointer-events: none !important; }
|
|
36
|
+
#comty-ui {
|
|
37
|
+
all: initial;
|
|
38
|
+
direction: ltr;
|
|
39
|
+
unicode-bidi: normal;
|
|
40
|
+
font-size: 16px;
|
|
41
|
+
line-height: 1.5;
|
|
42
|
+
text-align: left;
|
|
43
|
+
-webkit-text-size-adjust: none;
|
|
44
|
+
text-size-adjust: none;
|
|
8
45
|
--comty-surface: var(--comty-toolbar-surface);
|
|
9
46
|
--comty-hover-surface: var(--comty-toolbar-selected);
|
|
10
47
|
--comty-foreground: #fafafa;
|
|
@@ -75,13 +112,13 @@ export function getComtyStyle() {
|
|
|
75
112
|
font-family: var(--comty-font);
|
|
76
113
|
color-scheme: dark;
|
|
77
114
|
}
|
|
78
|
-
#comty-
|
|
79
|
-
#comty-
|
|
80
|
-
#comty-
|
|
81
|
-
#comty-
|
|
82
|
-
#comty-
|
|
83
|
-
#comty-
|
|
84
|
-
#comty-
|
|
115
|
+
#comty-ui :is(button, .comty-comment-avatar) { user-select: none; -webkit-user-select: none; }
|
|
116
|
+
#comty-ui .comty-comment-avatar img { -webkit-user-drag: none; }
|
|
117
|
+
#comty-ui .comty-pin .comty-comment-avatar { pointer-events: none; }
|
|
118
|
+
#comty-ui > .comty-agent-panel { position: fixed; right: 1rem; bottom: 5rem; z-index: 2147483647; width: min(22rem, calc(100vw - 2rem)); max-height: min(32rem, calc(100vh - 6rem)); box-sizing: border-box; display: flex; flex-direction: column; overflow: hidden; pointer-events: auto; border: .0625rem solid var(--comty-border); border-radius: 1rem; background: var(--comty-surface); box-shadow: var(--comty-floating-shadow); color: var(--comty-foreground); font: .875rem/1.4 ui-sans-serif, system-ui, sans-serif; transform: translateY(0); opacity: 1; transition: transform var(--comty-motion-duration) var(--comty-ease-out), opacity var(--comty-motion-duration) ease; color-scheme: dark; }
|
|
119
|
+
#comty-ui > .comty-agent-panel[data-side="left"] { left: 1rem; right: auto; }
|
|
120
|
+
#comty-ui > .comty-agent-panel[data-closed] { transform: translateY(.5rem); opacity: 0; pointer-events: none; }
|
|
121
|
+
#comty-ui > .comty-agent-panel[hidden] { display: none; }
|
|
85
122
|
.comty-agent-panel *, .comty-agent-panel *::before { box-sizing: border-box; }
|
|
86
123
|
.comty-agent-panel-header { display: flex; flex: 0 0 auto; align-items: center; gap: .75rem; padding: .5rem .75rem; border-bottom: .0625rem solid var(--comty-hover-surface); }
|
|
87
124
|
.comty-agent-brand { display: grid; place-items: center; width: 2.375rem; height: 2.375rem; flex-shrink: 0; border-radius: .6875rem; color: var(--comty-accent); background: var(--comty-hover-surface); }
|
|
@@ -112,9 +149,9 @@ export function getComtyStyle() {
|
|
|
112
149
|
.comty-agent-row-actions { display: flex; flex-shrink: 0; gap: .25rem; }
|
|
113
150
|
.comty-agent-panel .comty-agent-row-actions .comty-agent-action { min-height: 1.5rem; padding: .125rem .375rem; border-radius: .25rem; background: transparent; color: var(--comty-muted); font-size: .875rem; }
|
|
114
151
|
.comty-agent-panel .comty-agent-row-actions .comty-agent-action:hover { color: var(--comty-foreground); background: var(--comty-surface); }
|
|
115
|
-
#comty-
|
|
116
|
-
#comty-
|
|
117
|
-
#comty-
|
|
152
|
+
#comty-ui > .comty-agent-task-toast { position: fixed; right: 1rem; bottom: 1rem; z-index: 2147483647; width: min(20rem, calc(100vw - 2rem)); box-sizing: border-box; padding: .75rem 2rem .75rem .875rem; border: .0625rem solid var(--comty-border); border-radius: .75rem; background: var(--comty-surface); box-shadow: var(--comty-floating-shadow); color: var(--comty-foreground); font: .75rem/1.5 ui-sans-serif, system-ui, sans-serif; pointer-events: auto; opacity: 1; transform: translateY(0); transition: opacity 200ms ease, transform 200ms var(--comty-ease-out); animation: comty-agent-toast-in 200ms var(--comty-ease-out); color-scheme: dark; }
|
|
153
|
+
#comty-ui > .comty-agent-task-toast[data-toolbar] { right: auto; bottom: auto; }
|
|
154
|
+
#comty-ui > .comty-agent-task-toast[data-leaving] { opacity: 0; transform: translateY(.25rem); pointer-events: none; }
|
|
118
155
|
.comty-agent-task-toast strong { display: block; font-size: .8125rem; font-weight: 600; }
|
|
119
156
|
.comty-agent-task-toast p { margin: .25rem 0 0; color: var(--comty-muted); overflow-wrap: anywhere; }
|
|
120
157
|
.comty-agent-task-toast button { position: absolute; top: .5rem; right: .375rem; display: flex; align-items: center; justify-content: center; width: 1.5rem; height: 1.5rem; padding: 0; border: 0; border-radius: .25rem; background: transparent; color: var(--comty-muted); cursor: pointer; }
|
|
@@ -143,14 +180,8 @@ export function getComtyStyle() {
|
|
|
143
180
|
.comty-agent-working { position: fixed; z-index: 1; box-sizing: border-box; border: 2px solid var(--comty-accent); border-radius: 0; pointer-events: none; }
|
|
144
181
|
.comty-agent-working-badge { position: absolute; left: -.125rem; bottom: 100%; display: inline-flex; align-items: center; gap: .4rem; padding: .25rem .5rem; border-radius: .375rem .375rem 0 0; background: var(--comty-surface); color: var(--comty-foreground); font: 600 .6875rem/1.4 ui-sans-serif, system-ui, sans-serif; white-space: nowrap; }
|
|
145
182
|
.comty-agent-working[data-badge-below] .comty-agent-working-badge { bottom: auto; top: 100%; border-radius: 0 0 .375rem .375rem; }
|
|
146
|
-
#comty-
|
|
147
|
-
#comty-
|
|
148
|
-
html.comty-comment-placement,
|
|
149
|
-
html.comty-comment-placement body,
|
|
150
|
-
html.comty-comment-placement body *:not(#comty-root):not(#comty-root *) {
|
|
151
|
-
cursor: url("data:image/svg+xml,${encodeURIComponent(commentCursor)}") 16 16, crosshair !important;
|
|
152
|
-
}
|
|
153
|
-
#comty-root > .comty-sidepanel-open, #comty-root > .comty-pin, #comty-root > .comty-bubble, #comty-root > .comty-create-bubble, #comty-root > .comty-popover, #comty-root > .comty-auth-backdrop, #comty-root > .comty-auth-toast { pointer-events: auto; }
|
|
183
|
+
#comty-ui { cursor: default; }
|
|
184
|
+
#comty-ui > .comty-sidepanel-open, #comty-ui > .comty-pin, #comty-ui > .comty-bubble, #comty-ui > .comty-create-bubble, #comty-ui > .comty-popover, #comty-ui > .comty-auth-backdrop, #comty-ui > .comty-auth-toast { pointer-events: auto; }
|
|
154
185
|
.comty-toolbar {
|
|
155
186
|
position: absolute;
|
|
156
187
|
right: 1rem;
|
|
@@ -174,7 +205,7 @@ export function getComtyStyle() {
|
|
|
174
205
|
isolation: isolate;
|
|
175
206
|
transition: opacity 180ms ease, visibility 0s linear 180ms;
|
|
176
207
|
}
|
|
177
|
-
#comty-
|
|
208
|
+
#comty-ui.comty-active .comty-toolbar { opacity: 1; visibility: visible; pointer-events: auto; transition-delay: 0s; }
|
|
178
209
|
.comty-toolbar-surface { position: absolute; inset: 0; z-index: -1; border-radius: inherit; background: var(--comty-toolbar-surface); box-shadow: var(--comty-floating-shadow); transform-origin: top left; pointer-events: none; }
|
|
179
210
|
.comty-toolbar-grip { display: flex; align-items: center; justify-content: center; flex: 0 0 auto; width: var(--comty-toolbar-grip-width); height: var(--comty-tool-size); margin-inline-end: calc(var(--comty-toolbar-grip-gap) - var(--comty-toolbar-gap)); color: inherit; cursor: grab; }
|
|
180
211
|
.comty-toolbar-grip svg { width: 1.125rem; height: 1.125rem; flex-shrink: 0; }
|
|
@@ -212,10 +243,10 @@ export function getComtyStyle() {
|
|
|
212
243
|
.comty-filter-controls { display: flex; align-items: center; gap: .375rem; padding-inline: .5rem; }
|
|
213
244
|
.comty-filter-dot { flex-shrink: 0; width: .625rem; height: .625rem; padding: 0; border: 0; border-radius: 50%; cursor: pointer; }
|
|
214
245
|
.comty-filter-dot-muted { opacity: .35; }
|
|
215
|
-
#comty-
|
|
246
|
+
#comty-ui [hidden] { display: none !important; }
|
|
216
247
|
[data-comty-anchor-hidden] { visibility: hidden !important; pointer-events: none !important; }
|
|
217
248
|
@media (prefers-reduced-motion: reduce) {
|
|
218
|
-
.comty-toolbar, .comty-control-button, .comty-sidepanel, .comty-pin, .comty-bubble, .comty-agent-panel, .comty-agent-action, .comty-agent-dot, .comty-working-indicator > i, #comty-
|
|
249
|
+
.comty-toolbar, .comty-control-button, .comty-sidepanel, .comty-pin, .comty-bubble, .comty-agent-panel, .comty-agent-action, .comty-agent-dot, .comty-working-indicator > i, #comty-ui > .comty-agent-task-toast { transition: none !important; animation: none !important; }
|
|
219
250
|
}
|
|
220
251
|
|
|
221
252
|
.comty-sidepanel {
|
|
@@ -429,7 +460,7 @@ export function getComtyStyle() {
|
|
|
429
460
|
overflow: visible;
|
|
430
461
|
}
|
|
431
462
|
|
|
432
|
-
#comty-
|
|
463
|
+
#comty-ui > .comty-temp-pin { pointer-events: none; z-index: 2147483647; }
|
|
433
464
|
|
|
434
465
|
.comty-pin-icon {
|
|
435
466
|
display: block;
|
|
@@ -994,8 +1025,6 @@ export function getComtyStyle() {
|
|
|
994
1025
|
.comty-distance-arrow, .comty-distance-label, .comty-distance-snap { fill: currentColor; }
|
|
995
1026
|
.comty-distance-value { fill: var(--comty-paper); font: 500 .75rem var(--comty-font); }
|
|
996
1027
|
.comty-distance-announcement { position: absolute; width: .0625rem; height: .0625rem; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
|
|
997
|
-
html.comty-measure-vertical, html.comty-measure-vertical body *:not(#comty-root):not(#comty-root *) { cursor: ns-resize !important; }
|
|
998
|
-
html.comty-measure-horizontal, html.comty-measure-horizontal body *:not(#comty-root):not(#comty-root *) { cursor: ew-resize !important; }
|
|
999
1028
|
.comty-auth-toast { position: fixed; top: 16px; left: 50%; z-index: 2147483647; transform: translateX(-50%); padding: 9px 12px; border: 0; border-radius: 8px; background: var(--comty-surface); color: var(--comty-foreground); box-shadow: 0 8px 24px rgba(0,0,0,.15); font: 600 12px/1 sans-serif; }
|
|
1000
1029
|
.comty-auth-toast button { margin-left: .5rem; padding: .375rem .5rem; border: 0; border-radius: .375rem; background: var(--comty-accent); color: var(--comty-paper); cursor: pointer; font: inherit; }
|
|
1001
1030
|
|
|
@@ -1182,15 +1211,15 @@ export function getComtyStyle() {
|
|
|
1182
1211
|
margin: 4px 0;
|
|
1183
1212
|
}
|
|
1184
1213
|
|
|
1185
|
-
|
|
1214
|
+
#comty-ui:is(.comty-comments-active, .comty-inspect-annotations) .comty-pin {
|
|
1186
1215
|
display: grid;
|
|
1187
1216
|
}
|
|
1188
1217
|
|
|
1189
|
-
|
|
1218
|
+
#comty-ui:is(.comty-comments-active, .comty-inspect-annotations) .comty-pin.comty-filtered-out {
|
|
1190
1219
|
display: none;
|
|
1191
1220
|
}
|
|
1192
1221
|
|
|
1193
|
-
|
|
1222
|
+
#comty-ui:is(.comty-comments-active, .comty-inspect-annotations) .comty-bubble {
|
|
1194
1223
|
display: block;
|
|
1195
1224
|
}
|
|
1196
1225
|
|
|
@@ -1271,8 +1300,6 @@ export function getComtyStyle() {
|
|
|
1271
1300
|
.comty-ruler-guide-horizontal span { left: 1.5rem; top: .5rem; }
|
|
1272
1301
|
.comty-ruler-guide-vertical span { top: 1.5rem; left: .5rem; }
|
|
1273
1302
|
.comty-property-panel { position: fixed; z-index: 2147483646; width: max-content; max-width: calc(100vw - 1rem); max-height: calc(100vh - 1rem); box-sizing: border-box; margin: 0; padding: .375rem; border: 0; border-radius: 1rem; background: var(--comty-toolbar-group); color: var(--comty-foreground); box-shadow: var(--comty-floating-shadow); font: var(--comty-property-font-size)/1.4 var(--comty-font); pointer-events: auto; overflow-x: hidden; overflow-y: auto; }
|
|
1274
|
-
html[data-comty-property-picking="color"], html[data-comty-property-picking="color"] body, html[data-comty-property-picking="color"] body :not(#comty-root):not(#comty-root *) { cursor: none !important; }
|
|
1275
|
-
html[data-comty-property-picking="font"] body :not(#comty-root):not(#comty-root *) { cursor: url("data:image/svg+xml,${encodeURIComponent(typographyCursor)}") 2 2, default !important; }
|
|
1276
1303
|
.comty-property-panel[data-expanded] { width: var(--comty-property-width); }
|
|
1277
1304
|
.comty-property-panel[hidden] { display: none; }
|
|
1278
1305
|
.comty-color-magnifier { --comty-lens-rim: var(--comty-paper); --comty-lens-line: var(--comty-magnifier-gray); position: fixed; z-index: 2147483647; width: var(--comty-magnifier-size); height: var(--comty-magnifier-size); padding: var(--comty-magnifier-rim); box-sizing: border-box; border-radius: 50%; background: var(--comty-lens-rim); box-shadow: var(--comty-magnifier-shadow); transform: translate(-50%, -50%); pointer-events: none; }
|
|
@@ -1330,7 +1357,7 @@ export function getComtyStyle() {
|
|
|
1330
1357
|
.comty-motion-panel button[aria-pressed="true"] { opacity: 1; color: var(--comty-paper); background: var(--comty-hover-surface); }
|
|
1331
1358
|
.comty-motion-panel button[aria-pressed="false"] { opacity: 1; }
|
|
1332
1359
|
.comty-motion-panel [data-motion-status] { margin: .5rem; font-size: .75rem; color: var(--comty-muted); }
|
|
1333
|
-
@media (max-width: 38rem) { #comty-
|
|
1360
|
+
@media (max-width: 38rem) { #comty-ui { --comty-tool-size: 2rem; --comty-toolbar-padding: .25rem; } .comty-toolbar { right: .5rem; bottom: .5rem; max-width: calc(100vw - 1rem); flex-wrap: wrap; justify-content: center; row-gap: .25rem; } .comty-tool-divider { display: none; } }
|
|
1334
1361
|
|
|
1335
1362
|
.comty-inspection-box {
|
|
1336
1363
|
position: fixed;
|
|
@@ -1616,5 +1643,5 @@ export function getComtyStyle() {
|
|
|
1616
1643
|
}
|
|
1617
1644
|
.comty-create-bubble { animation: none; }
|
|
1618
1645
|
}
|
|
1619
|
-
|
|
1646
|
+
`.replace(/(-?(?:\d*\.)?\d+)rem\b/g, (_, value) => `${Number(value) * 16}px`);
|
|
1620
1647
|
}
|
package/src/vite.mjs
CHANGED
|
@@ -1,69 +1,154 @@
|
|
|
1
|
-
import { readFile } from
|
|
2
|
-
import { createCompanion, isLoopback } from
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { createCompanion, isLoopback } from "./companion.mjs";
|
|
3
3
|
|
|
4
4
|
/** Starts the local companion on Vite's own origin, without a second port. */
|
|
5
5
|
export function comty(options = {}) {
|
|
6
6
|
let companion, origin, start;
|
|
7
7
|
return {
|
|
8
|
-
name:
|
|
8
|
+
name: "comty",
|
|
9
|
+
apply: "serve",
|
|
9
10
|
configureServer(server) {
|
|
10
11
|
const host = server.config.server.host;
|
|
11
|
-
if (host === true || (typeof host ===
|
|
12
|
-
throw new Error(
|
|
12
|
+
if (host === true || (typeof host === "string" && !isLoopback(host))) {
|
|
13
|
+
throw new Error(
|
|
14
|
+
"Comty Agent requires Vite to bind localhost or 127.0.0.1",
|
|
15
|
+
);
|
|
13
16
|
}
|
|
14
|
-
if (!server.httpServer)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
if (!server.httpServer)
|
|
18
|
+
throw new Error(
|
|
19
|
+
"Comty requires a Vite HTTP server (middleware mode is unsupported)",
|
|
20
|
+
);
|
|
21
|
+
const runtime = new URL("./browser.js", import.meta.url);
|
|
22
|
+
const style = new URL("./style.js", import.meta.url);
|
|
23
|
+
const anchors = new URL("./anchors.js", import.meta.url);
|
|
24
|
+
const resilientAnchors = new URL(
|
|
25
|
+
"./resilient-anchor.js",
|
|
26
|
+
import.meta.url,
|
|
27
|
+
);
|
|
28
|
+
const capture = new URL("./capture.js", import.meta.url);
|
|
29
|
+
const captureEngine = new URL("./capture-engine.js", import.meta.url);
|
|
30
|
+
const captureResources = new URL(
|
|
31
|
+
"./capture-resources.js",
|
|
32
|
+
import.meta.url,
|
|
33
|
+
);
|
|
34
|
+
const comments = new URL("./comments.js", import.meta.url);
|
|
35
|
+
const measurements = new URL("./measurements.js", import.meta.url);
|
|
36
|
+
const markup = new URL("./inspect-markup.js", import.meta.url);
|
|
24
37
|
start = new Promise((resolve, reject) => {
|
|
25
|
-
const onError = error => {
|
|
38
|
+
const onError = (error) => {
|
|
26
39
|
// Vite retries the next port after EADDRINUSE unless strictPort is set.
|
|
27
|
-
if (error.code !==
|
|
40
|
+
if (error.code !== "EADDRINUSE" || server.config.server.strictPort)
|
|
41
|
+
reject(error);
|
|
28
42
|
};
|
|
29
|
-
server.httpServer.on(
|
|
30
|
-
server.httpServer.once(
|
|
31
|
-
server.httpServer.off(
|
|
43
|
+
server.httpServer.on("error", onError);
|
|
44
|
+
server.httpServer.once("listening", () => {
|
|
45
|
+
server.httpServer.off("error", onError);
|
|
32
46
|
try {
|
|
33
47
|
const address = server.httpServer.address();
|
|
34
|
-
const hostname = typeof host ===
|
|
35
|
-
origin = `${server.config.server.https ?
|
|
36
|
-
companion = createCompanion({
|
|
37
|
-
|
|
48
|
+
const hostname = typeof host === "string" ? host : "localhost";
|
|
49
|
+
origin = `${server.config.server.https ? "https" : "http"}://${hostname}:${address.port}`;
|
|
50
|
+
companion = createCompanion({
|
|
51
|
+
cwd: server.config.root,
|
|
52
|
+
origin,
|
|
53
|
+
provider: options.agent,
|
|
54
|
+
model: options.model,
|
|
55
|
+
});
|
|
56
|
+
server.httpServer.once("close", () => {
|
|
57
|
+
void companion
|
|
58
|
+
.close()
|
|
59
|
+
.catch((error) =>
|
|
60
|
+
server.config.logger.error(`Comty: ${error.message}`),
|
|
61
|
+
);
|
|
62
|
+
});
|
|
38
63
|
resolve();
|
|
39
|
-
} catch (error) {
|
|
64
|
+
} catch (error) {
|
|
65
|
+
reject(error);
|
|
66
|
+
}
|
|
40
67
|
});
|
|
41
68
|
});
|
|
42
|
-
start.catch(error =>
|
|
69
|
+
start.catch((error) =>
|
|
70
|
+
server.config.logger.error(`Comty: ${error.message}`),
|
|
71
|
+
);
|
|
43
72
|
server.middlewares.use(async (request, response, next) => {
|
|
44
|
-
if (!request.url?.startsWith(
|
|
73
|
+
if (!request.url?.startsWith("/__comty/")) return next();
|
|
45
74
|
try {
|
|
46
75
|
await start;
|
|
47
|
-
if (
|
|
48
|
-
|
|
76
|
+
if (
|
|
77
|
+
request.headers.host !== new URL(origin).host ||
|
|
78
|
+
(request.headers.origin && request.headers.origin !== origin)
|
|
79
|
+
) {
|
|
80
|
+
response.writeHead(403);
|
|
81
|
+
response.end();
|
|
82
|
+
return;
|
|
49
83
|
}
|
|
50
84
|
const path = new URL(request.url, origin).pathname;
|
|
51
|
-
if (
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
85
|
+
if (
|
|
86
|
+
request.method === "GET" &&
|
|
87
|
+
[
|
|
88
|
+
"/__comty/browser.js",
|
|
89
|
+
"/__comty/style.js",
|
|
90
|
+
"/__comty/anchors.js",
|
|
91
|
+
"/__comty/resilient-anchor.js",
|
|
92
|
+
"/__comty/capture.js",
|
|
93
|
+
"/__comty/capture-engine.js",
|
|
94
|
+
"/__comty/capture-resources.js",
|
|
95
|
+
"/__comty/comments.js",
|
|
96
|
+
"/__comty/measurements.js",
|
|
97
|
+
"/__comty/inspect-markup.js",
|
|
98
|
+
"/__comty/start.js",
|
|
99
|
+
].includes(path)
|
|
100
|
+
) {
|
|
101
|
+
response.setHeader("Content-Type", "text/javascript");
|
|
102
|
+
response.setHeader("Cache-Control", "no-store");
|
|
103
|
+
response.setHeader("X-Content-Type-Options", "nosniff");
|
|
104
|
+
response.end(
|
|
105
|
+
path.endsWith("/browser.js")
|
|
106
|
+
? await readFile(runtime)
|
|
107
|
+
: path.endsWith("/style.js")
|
|
108
|
+
? await readFile(style)
|
|
109
|
+
: path.endsWith("/anchors.js")
|
|
110
|
+
? await readFile(anchors)
|
|
111
|
+
: path.endsWith("/resilient-anchor.js")
|
|
112
|
+
? await readFile(resilientAnchors)
|
|
113
|
+
: path.endsWith("/capture.js")
|
|
114
|
+
? await readFile(capture)
|
|
115
|
+
: path.endsWith("/capture-engine.js")
|
|
116
|
+
? await readFile(captureEngine)
|
|
117
|
+
: path.endsWith("/capture-resources.js")
|
|
118
|
+
? await readFile(captureResources)
|
|
119
|
+
: path.endsWith("/comments.js")
|
|
120
|
+
? await readFile(comments)
|
|
121
|
+
: path.endsWith("/measurements.js")
|
|
122
|
+
? await readFile(measurements)
|
|
123
|
+
: path.endsWith("/inspect-markup.js")
|
|
124
|
+
? await readFile(markup)
|
|
125
|
+
: `import { initComty } from '/__comty/browser.js';\ninitComty(${JSON.stringify({ projectKey: options.projectKey, apiUrl: options.apiUrl, agent: { url: `${origin}/__comty`, token: companion.token } })}).catch(console.error);`,
|
|
126
|
+
);
|
|
56
127
|
} else await companion.handle(request, response);
|
|
57
|
-
} catch (error) {
|
|
128
|
+
} catch (error) {
|
|
129
|
+
next(error);
|
|
130
|
+
}
|
|
58
131
|
});
|
|
59
132
|
},
|
|
60
133
|
transformIndexHtml: {
|
|
61
|
-
order:
|
|
134
|
+
order: "pre",
|
|
62
135
|
async handler() {
|
|
63
136
|
await start;
|
|
64
|
-
return [
|
|
137
|
+
return [
|
|
138
|
+
{
|
|
139
|
+
tag: "script",
|
|
140
|
+
attrs: {
|
|
141
|
+
type: "module",
|
|
142
|
+
src: "/__comty/start.js",
|
|
143
|
+
"vite-ignore": "",
|
|
144
|
+
},
|
|
145
|
+
injectTo: "head-prepend",
|
|
146
|
+
},
|
|
147
|
+
];
|
|
65
148
|
},
|
|
66
149
|
},
|
|
67
|
-
async closeBundle() {
|
|
150
|
+
async closeBundle() {
|
|
151
|
+
await companion?.close();
|
|
152
|
+
},
|
|
68
153
|
};
|
|
69
154
|
}
|