@comty.io/core 0.1.8 → 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/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
- #comty-root {
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-root :is(button, .comty-comment-avatar) { user-select: none; -webkit-user-select: none; }
79
- #comty-root .comty-comment-avatar img { -webkit-user-drag: none; }
80
- #comty-root .comty-pin .comty-comment-avatar { pointer-events: none; }
81
- #comty-root > .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; }
82
- #comty-root > .comty-agent-panel[data-side="left"] { left: 1rem; right: auto; }
83
- #comty-root > .comty-agent-panel[data-closed] { transform: translateY(.5rem); opacity: 0; pointer-events: none; }
84
- #comty-root > .comty-agent-panel[hidden] { display: none; }
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-root > .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; }
116
- #comty-root > .comty-agent-task-toast[data-toolbar] { right: auto; bottom: auto; }
117
- #comty-root > .comty-agent-task-toast[data-leaving] { opacity: 0; transform: translateY(.25rem); pointer-events: none; }
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-root { cursor: default; }
147
- #comty-root::backdrop { background: transparent; pointer-events: none; }
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-root.comty-active .comty-toolbar { opacity: 1; visibility: visible; pointer-events: auto; transition-delay: 0s; }
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-root [hidden] { display: none !important; }
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-root > .comty-agent-task-toast { transition: none !important; animation: none !important; }
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-root > .comty-temp-pin { pointer-events: none; z-index: 2147483647; }
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
- html:is(.comty-comments-active, .comty-inspect-annotations) .comty-pin {
1214
+ #comty-ui:is(.comty-comments-active, .comty-inspect-annotations) .comty-pin {
1186
1215
  display: grid;
1187
1216
  }
1188
1217
 
1189
- html:is(.comty-comments-active, .comty-inspect-annotations) .comty-pin.comty-filtered-out {
1218
+ #comty-ui:is(.comty-comments-active, .comty-inspect-annotations) .comty-pin.comty-filtered-out {
1190
1219
  display: none;
1191
1220
  }
1192
1221
 
1193
- html:is(.comty-comments-active, .comty-inspect-annotations) .comty-bubble {
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-root { --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; } }
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 'node:fs/promises';
2
- import { createCompanion, isLoopback } from './companion.mjs';
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: 'comty', apply: 'serve',
8
+ name: "comty",
9
+ apply: "serve",
9
10
  configureServer(server) {
10
11
  const host = server.config.server.host;
11
- if (host === true || (typeof host === 'string' && !isLoopback(host))) {
12
- throw new Error('Comty Agent requires Vite to bind localhost or 127.0.0.1');
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) throw new Error('Comty requires a Vite HTTP server (middleware mode is unsupported)');
15
- const runtime = new URL('./browser.js', import.meta.url);
16
- const style = new URL('./style.js', import.meta.url);
17
- const anchors = new URL('./anchors.js', import.meta.url);
18
- const capture = new URL('./capture.js', import.meta.url);
19
- const captureEngine = new URL('./capture-engine.js', import.meta.url);
20
- const captureResources = new URL('./capture-resources.js', import.meta.url);
21
- const comments = new URL('./comments.js', import.meta.url);
22
- const measurements = new URL('./measurements.js', import.meta.url);
23
- const markup = new URL('./inspect-markup.js', import.meta.url);
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 !== 'EADDRINUSE' || server.config.server.strictPort) reject(error);
40
+ if (error.code !== "EADDRINUSE" || server.config.server.strictPort)
41
+ reject(error);
28
42
  };
29
- server.httpServer.on('error', onError);
30
- server.httpServer.once('listening', () => {
31
- server.httpServer.off('error', onError);
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 === 'string' ? host : 'localhost';
35
- origin = `${server.config.server.https ? 'https' : 'http'}://${hostname}:${address.port}`;
36
- companion = createCompanion({ cwd: server.config.root, origin, provider: options.agent, model: options.model });
37
- server.httpServer.once('close', () => { void companion.close().catch(error => server.config.logger.error(`Comty: ${error.message}`)); });
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) { reject(error); }
64
+ } catch (error) {
65
+ reject(error);
66
+ }
40
67
  });
41
68
  });
42
- start.catch(error => server.config.logger.error(`Comty: ${error.message}`));
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('/__comty/')) return next();
73
+ if (!request.url?.startsWith("/__comty/")) return next();
45
74
  try {
46
75
  await start;
47
- if (request.headers.host !== new URL(origin).host || (request.headers.origin && request.headers.origin !== origin)) {
48
- response.writeHead(403); response.end(); return;
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 (request.method === 'GET' && ['/__comty/browser.js', '/__comty/style.js', '/__comty/anchors.js', '/__comty/capture.js', '/__comty/capture-engine.js', '/__comty/capture-resources.js', '/__comty/comments.js', '/__comty/measurements.js', '/__comty/inspect-markup.js', '/__comty/start.js'].includes(path)) {
52
- response.setHeader('Content-Type', 'text/javascript'); response.setHeader('Cache-Control', 'no-store');
53
- response.setHeader('X-Content-Type-Options', 'nosniff');
54
- response.end(path.endsWith('/browser.js') ? await readFile(runtime) : path.endsWith('/style.js') ? await readFile(style) : path.endsWith('/anchors.js') ? await readFile(anchors) : path.endsWith('/capture.js') ? await readFile(capture) : path.endsWith('/capture-engine.js') ? await readFile(captureEngine) : path.endsWith('/capture-resources.js') ? await readFile(captureResources) : path.endsWith('/comments.js') ? await readFile(comments) : path.endsWith('/measurements.js') ? await readFile(measurements) : path.endsWith('/inspect-markup.js') ? await readFile(markup) :
55
- `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);`);
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) { next(error); }
128
+ } catch (error) {
129
+ next(error);
130
+ }
58
131
  });
59
132
  },
60
133
  transformIndexHtml: {
61
- order: 'pre',
134
+ order: "pre",
62
135
  async handler() {
63
136
  await start;
64
- return [{ tag: 'script', attrs: { type: 'module', src: '/__comty/start.js', 'vite-ignore': '' }, injectTo: 'head-prepend' }];
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() { await companion?.close(); },
150
+ async closeBundle() {
151
+ await companion?.close();
152
+ },
68
153
  };
69
154
  }