@snagset/server 0.0.1 → 0.0.2

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/dist/app.js CHANGED
@@ -13,6 +13,7 @@ import { commentRoutes } from "./routes/comments.js";
13
13
  import { commentEditRoutes } from "./routes/commentEdit.js";
14
14
  import { corsForProjects } from "./routes/cors.js";
15
15
  import { bearerAuth } from "./routes/auth.js";
16
+ import { createReviewerCache } from "./reviewerCache.js";
16
17
  import { attachmentRoutes, features } from "./routes/attachments.js";
17
18
  import { sessionRoutes } from "./routes/sessions.js";
18
19
  import { reviewLinkRoutes } from "./routes/reviewLinks.js";
@@ -48,6 +49,10 @@ export function createApp(deps) {
48
49
  // `session_epoch` revocation cost nothing per request (05 §4.4).
49
50
  const keys = createKeyring(deps.secretKey, cfg.get("SNAGSET_SECRET_KEY_PREVIOUS"));
50
51
  const projects = createProjectCache(sql);
52
+ /** Per-identity revocation, same ten-second window as the project cache
53
+ * (05 §4.6). Its absence is what let a signed-out reviewer keep working
54
+ * until their token refreshed. */
55
+ const reviewers = createReviewerCache(sql);
51
56
  const ttls = {
52
57
  slidingS: cfg.int("SNAGSET_SESSION_TTL_S"),
53
58
  absoluteS: cfg.int("SNAGSET_SESSION_ABSOLUTE_TTL_S"),
@@ -271,15 +276,15 @@ export function createApp(deps) {
271
276
  // After CORS, before the routes: a session is ATTACHED when one verifies and
272
277
  // the route decides whether it needed one. `/sessions` is excluded — it is
273
278
  // where a bearer is exchanged, not presented.
274
- app.use("/api/v1/projects/:uid/threads", bearerAuth(keys, projects, ttls.absoluteS));
275
- app.use("/api/v1/projects/:uid/threads/*", bearerAuth(keys, projects, ttls.absoluteS));
279
+ app.use("/api/v1/projects/:uid/threads", bearerAuth(keys, projects, ttls.absoluteS, reviewers));
280
+ app.use("/api/v1/projects/:uid/threads/*", bearerAuth(keys, projects, ttls.absoluteS, reviewers));
276
281
  // The dashboard's unscoped form, `/api/v1/threads/{id}/comments` — no `:uid`
277
282
  // segment for `bearerAuth` to read, so this mount is a no-op today (it
278
283
  // returns immediately whenever its own `uid` param is absent). Added anyway
279
284
  // so the credential-attaching middleware for this surface is declared once,
280
285
  // per path, the same way every other one here is — not discovered missing
281
286
  // the day a bearer-carrying caller of the unscoped form shows up.
282
- app.use("/api/v1/threads/*", bearerAuth(keys, projects, ttls.absoluteS));
287
+ app.use("/api/v1/threads/*", bearerAuth(keys, projects, ttls.absoluteS, reviewers));
283
288
  app.route("/", sessionRoutes({ sql, keys, projects, ttls }));
284
289
  // Whether to QUEUE a notification at all — see CommentDeps.notifications.
285
290
  // Computed once at construction: the transport cannot change without a
@@ -293,10 +298,10 @@ export function createApp(deps) {
293
298
  * session is a legitimate credential on these paths, so `requireOwner()`
294
299
  * must not stand in front of them.
295
300
  */
296
- app.use("/api/v1/comments/*", bearerAuth(keys, projects, ttls.absoluteS));
297
- app.use("/api/v1/projects/:uid/comments/*", bearerAuth(keys, projects, ttls.absoluteS));
301
+ app.use("/api/v1/comments/*", bearerAuth(keys, projects, ttls.absoluteS, reviewers));
302
+ app.use("/api/v1/projects/:uid/comments/*", bearerAuth(keys, projects, ttls.absoluteS, reviewers));
298
303
  app.route("/", commentEditRoutes({ sql }));
299
- app.use("/api/v1/projects/:uid/attachments", bearerAuth(keys, projects, ttls.absoluteS));
304
+ app.use("/api/v1/projects/:uid/attachments", bearerAuth(keys, projects, ttls.absoluteS, reviewers));
300
305
  app.route("/", attachmentRoutes({
301
306
  sql,
302
307
  keys,
package/dist/app.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ export function createReviewerCache(sql, opts = {}) {
2
+ const ttl = opts.ttlMs ?? 10_000;
3
+ const now = opts.now ?? (() => Date.now());
4
+ const entries = new Map();
5
+ const inflight = new Map();
6
+ async function load(id) {
7
+ const [row] = await sql `
8
+ SELECT identity_valid_after FROM reviewers WHERE id = ${id}::uuid
9
+ `;
10
+ return row?.identity_valid_after ?? null;
11
+ }
12
+ return {
13
+ async validAfter(reviewerId) {
14
+ const hit = entries.get(reviewerId);
15
+ if (hit && now() - hit.at < ttl)
16
+ return hit.value;
17
+ const running = inflight.get(reviewerId);
18
+ if (running)
19
+ return running;
20
+ const p = load(reviewerId)
21
+ .then((value) => {
22
+ entries.set(reviewerId, { at: now(), value });
23
+ return value;
24
+ })
25
+ .finally(() => inflight.delete(reviewerId));
26
+ inflight.set(reviewerId, p);
27
+ return p;
28
+ },
29
+ invalidate(reviewerId) {
30
+ entries.delete(reviewerId);
31
+ },
32
+ };
33
+ }
34
+ //# sourceMappingURL=reviewerCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviewerCache.js","sourceRoot":"","sources":["../src/reviewerCache.ts"],"names":[],"mappings":"AAyDA,MAAM,UAAU,mBAAmB,CACjC,GAAiB,EACjB,OAA+C,EAAE;IAEjD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC;IACjC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAiB,CAAC;IACzC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAgC,CAAC;IAEzD,KAAK,UAAU,IAAI,CAAC,EAAU;QAC5B,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,GAAG,CAAyC;8DACN,EAAE;KAC3D,CAAC;QACF,OAAO,GAAG,EAAE,oBAAoB,IAAI,IAAI,CAAC;IAC3C,CAAC;IAED,OAAO;QACL,KAAK,CAAC,UAAU,CAAC,UAAU;YACzB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YACpC,IAAI,GAAG,IAAI,GAAG,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG;gBAAE,OAAO,GAAG,CAAC,KAAK,CAAC;YAElD,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YACzC,IAAI,OAAO;gBAAE,OAAO,OAAO,CAAC;YAE5B,MAAM,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC;iBACvB,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;gBACd,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;gBAC9C,OAAO,KAAK,CAAC;YACf,CAAC,CAAC;iBACD,OAAO,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;YAC9C,QAAQ,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YAC5B,OAAO,CAAC,CAAC;QACX,CAAC;QACD,UAAU,CAAC,UAAU;YACnB,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC7B,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -18,7 +18,11 @@ import { verifySession } from "../session.js";
18
18
  * reported: a reviewer whose link was revoked mid-session needs F-19, not a
19
19
  * silent downgrade to read-only that looks like the widget quietly breaking.
20
20
  */
21
- export function bearerAuth(keys, projects, absoluteTtlS) {
21
+ export function bearerAuth(keys, projects, absoluteTtlS,
22
+ /** Per-identity revocation (05 §4.6). Optional so existing callers and
23
+ * tests keep working; without it the check falls back to refresh-time
24
+ * only, which is the behaviour this argument exists to end. */
25
+ reviewers) {
22
26
  return async (c, next) => {
23
27
  const token = /^Bearer (.+)$/i.exec(c.req.header("Authorization") ?? "")?.[1];
24
28
  const uid = c.req.param("uid");
@@ -33,6 +37,33 @@ export function bearerAuth(keys, projects, absoluteTtlS) {
33
37
  absoluteTtlS,
34
38
  });
35
39
  if (v.ok) {
40
+ /**
41
+ * PER-IDENTITY REVOCATION — 05 §4.6 / §1601's "10-second cache miss
42
+ * path", which existed in the spec and not in the code.
43
+ *
44
+ * `session_epoch` above revokes a whole project's links and costs
45
+ * nothing, because the project row was already in memory. This is the
46
+ * other case: ONE person signed out — what a host app's logout hook
47
+ * calls — while the round carries on for everybody else. It was checked
48
+ * only when a token refreshed, so a signed-out reviewer kept working
49
+ * for up to the 15-minute sliding TTL.
50
+ *
51
+ * Cached ten seconds per reviewer rather than read per request, because
52
+ * this middleware makes no database call at all and that is worth
53
+ * keeping. `iat` is seconds; the column is a timestamp.
54
+ */
55
+ if (reviewers) {
56
+ const validAfter = await reviewers.validAfter(v.claims.sub).catch(() => null);
57
+ if (validAfter && v.claims.iat * 1000 < validAfter.getTime()) {
58
+ return c.json({
59
+ error: {
60
+ code: "session_revoked",
61
+ message: "This reviewer has been signed out.",
62
+ requestId: c.get("requestId"),
63
+ },
64
+ }, 401);
65
+ }
66
+ }
36
67
  c.set("session", v.claims);
37
68
  return next();
38
69
  }
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/routes/auth.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAsB,MAAM,eAAe,CAAC;AAElE;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,UAAU,CAAC,IAAa,EAAE,QAAsB,EAAE,YAAoB;IACpF,OAAO,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;QACvB,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9E,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,EAAE,CAAC;QAElC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAC1D,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,EAAE,CAAC;QAE5B,MAAM,CAAC,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,KAAK,EAAE;YACzC,UAAU,EAAE,GAAG;YACf,aAAa,EAAE,OAAO,CAAC,aAAa;YACpC,YAAY;SACb,CAAC,CAAC;QAEH,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC;YACT,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,MAAuB,CAAC,CAAC;YAC5C,OAAO,IAAI,EAAE,CAAC;QAChB,CAAC;QAED,sEAAsE;QACtE,wEAAwE;QACxE,wEAAwE;QACxE,0DAA0D;QAC1D,IAAI,CAAC,CAAC,MAAM,KAAK,iBAAiB,EAAE,CAAC;YACnC,OAAO,CAAC,CAAC,IAAI,CACX;gBACE,KAAK,EAAE;oBACL,IAAI,EAAE,iBAAiB;oBACvB,OAAO,EAAE,qEAAqE;oBAC9E,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC;iBAC9B;aACF,EACD,GAAG,CACJ,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,EAAE,CAAC;IAChB,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/routes/auth.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAsB,MAAM,eAAe,CAAC;AAElE;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,UAAU,CACxB,IAAa,EACb,QAAsB,EACtB,YAAoB;AACpB;;gEAEgE;AAChE,SAAyB;IAEzB,OAAO,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;QACvB,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9E,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,EAAE,CAAC;QAElC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAC1D,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,EAAE,CAAC;QAE5B,MAAM,CAAC,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,KAAK,EAAE;YACzC,UAAU,EAAE,GAAG;YACf,aAAa,EAAE,OAAO,CAAC,aAAa;YACpC,YAAY;SACb,CAAC,CAAC;QAEH,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC;YACT;;;;;;;;;;;;;;eAcG;YACH,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;gBAC9E,IAAI,UAAU,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,GAAG,IAAI,GAAG,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC;oBAC7D,OAAO,CAAC,CAAC,IAAI,CACX;wBACE,KAAK,EAAE;4BACL,IAAI,EAAE,iBAAiB;4BACvB,OAAO,EAAE,oCAAoC;4BAC7C,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC;yBAC9B;qBACF,EACD,GAAG,CACJ,CAAC;gBACJ,CAAC;YACH,CAAC;YACD,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,MAAuB,CAAC,CAAC;YAC5C,OAAO,IAAI,EAAE,CAAC;QAChB,CAAC;QAED,sEAAsE;QACtE,wEAAwE;QACxE,wEAAwE;QACxE,0DAA0D;QAC1D,IAAI,CAAC,CAAC,MAAM,KAAK,iBAAiB,EAAE,CAAC;YACnC,OAAO,CAAC,CAAC,IAAI,CACX;gBACE,KAAK,EAAE;oBACL,IAAI,EAAE,iBAAiB;oBACvB,OAAO,EAAE,qEAAqE;oBAC9E,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC;iBAC9B;aACF,EACD,GAAG,CACJ,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,EAAE,CAAC;IAChB,CAAC,CAAC;AACJ,CAAC"}
@@ -150,6 +150,7 @@ export const storageKey = {
150
150
  session: (uid) => `snag:session:${uid}`,
151
151
  identity: IDENTITY_KEY,
152
152
  threads: (uid, env) => `snag:threads:${uid}:${env}`,
153
+ seen: (uid, env) => `snag:seen:${uid}:${env}`,
153
154
  counts: (origin) => `snag:counts:${origin}`,
154
155
  draft: (route, draftId) => `snag:draft:${route}:${draftId}`,
155
156
  outbox: (uid) => `snag:outbox:${uid}`,
@@ -169,6 +170,7 @@ export const STORAGE_KEY_PATTERNS = [
169
170
  "^snag:session:.+$",
170
171
  "^snag:identity$",
171
172
  "^snag:threads:.+:.+$",
173
+ "^snag:seen:.+:.+$",
172
174
  "^snag:counts:.+$",
173
175
  "^snag:draft:.+:.+$",
174
176
  "^snag:outbox:.+$",
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@snagset/server",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "private": false,
5
5
  "type": "module",
6
- "description": "The Snagset server (D63: the npm name `snagset` belongs to the MIT widget; this is what a `create-snagset` repo depends on) — Hono API + widget assets + dashboard statics + migrations, compiled into the one published npm package (foundations §10, LOCK L5/L7). Two entry points on the same createApp(deps): the Vercel serverless handler and the npx bin.",
6
+ "description": "The Snagset server: API, dashboard and widget in one package. Node and Postgres, or Vercel.",
7
7
  "license": "AGPL-3.0-only",
8
8
  "bin": {
9
9
  "snagset": "./dist/bin.js"
@@ -0,0 +1 @@
1
+ :root{color-scheme:light dark;--ink: #181716;--ink-soft: #585755;--ink-faint: #6b6a68;--bg: #faf8f6;--surface: #fefdfc;--line: #e4e3e0;--line-soft: #eeecea;--line-strong: #939290;--accent: #2a51b8;--on-accent: #ffffff;--accent-soft: #e9f0ff;--warn: #9a2929;--open: #006f96;--progress: #9c542b;--review: #725ba1;--resolved: #417332;--mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;--sans: system-ui, -apple-system, "Segoe UI", Inter, sans-serif;--radius: 6px}@media(prefers-color-scheme:dark){:root{--ink: #f0eeec;--ink-soft: #a7a6a4;--ink-faint: #8e8c8b;--bg: #100f0e;--surface: #1d1c1a;--line: #2e2c2b;--line-soft: #242321;--line-strong: #696866;--accent: #8aafff;--on-accent: #100f0e;--accent-soft: #17223b;--warn: #ed8c84;--open: #3b9dc8;--progress: #cd8058;--review: #9e87d1;--resolved: #6ca05d}}*{box-sizing:border-box}body{margin:0;font:14px/1.5 var(--sans);color:var(--ink);background:var(--bg);-webkit-font-smoothing:antialiased}button{font:inherit;color:inherit}.shell{display:flex;flex-direction:column;height:100vh;overflow:hidden}.topbar{display:flex;align-items:center;gap:16px;padding:0 16px;height:52px;flex:none;border-bottom:1px solid var(--line);background:var(--surface)}.brand{font-weight:620;letter-spacing:-.01em;margin-inline-end:4px}.brand span{color:var(--ink-faint);font-weight:400}.topbar select{font:inherit;padding:4px 8px;border:1px solid var(--line-strong);border-radius:var(--radius);background:var(--surface);color:inherit}.spacer{flex:1}.who{color:var(--ink-soft);font-size:13px}.linkish{background:none;border:0;padding:4px 6px;color:var(--ink-soft);cursor:pointer;border-radius:var(--radius)}.linkish:hover{background:var(--line-soft);color:var(--ink)}.inbox{flex:1;display:grid;grid-template-columns:minmax(300px,380px) 1fr;min-height:0;overflow:hidden}@media(max-width:900px){.inbox{grid-template-columns:1fr}.inbox>.detail:not(.detail-open){display:none}}.list{border-inline-end:1px solid var(--line);background:var(--surface);display:flex;flex-direction:column;min-height:0}.filters{display:flex;gap:6px;padding:10px 12px;border-bottom:1px solid var(--line-soft);flex-wrap:wrap;align-items:center}.filters input[type=search]{font:inherit;flex:1;min-width:120px;padding:5px 9px;border:1px solid var(--line-strong);border-radius:var(--radius);background:var(--bg);color:inherit}.chip{font:500 12px/1 var(--sans);padding:5px 9px;border:1px solid var(--line-strong);border-radius:999px;background:transparent;color:var(--ink-soft);cursor:pointer}.chip[aria-pressed=true]{background:var(--accent-soft);border-color:transparent;color:var(--ink);font-weight:600}.rows{overflow-y:auto;flex:1}.row{display:block;width:100%;text-align:start;border:0;border-bottom:1px solid var(--line-soft);background:none;padding:11px 12px;cursor:pointer}.row:hover{background:var(--line-soft)}.row[aria-current=true]{background:var(--accent-soft);border-inline-start:3px solid var(--accent);padding-inline-start:9px}.row:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}.row-top{display:flex;align-items:center;gap:8px}.key{font:600 12px/1 var(--mono);color:var(--ink-faint)}.row-body{margin:4px 0 0;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.row-meta{margin-top:5px;font-size:12px;color:var(--ink-faint);display:flex;gap:8px}.status{font:600 11px/1 var(--sans);text-transform:uppercase;letter-spacing:.04em;padding:3px 7px;border-radius:999px;border:1px solid currentColor}.status-open{color:var(--open)}.status-progress{color:var(--progress)}.status-review{color:var(--review)}.status-resolved{color:var(--resolved)}.detail{overflow-y:auto;min-height:0;padding:22px 26px 60px}.detail-head{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}.detail-head h1{font:600 19px/1.3 var(--sans);margin:0;letter-spacing:-.01em}.shot{margin:18px 0;border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;background:var(--surface)}.shot img{display:block;width:100%;height:auto}.shot figcaption{font:12px/1.4 var(--mono);color:var(--ink-faint);padding:7px 10px;border-top:1px solid var(--line-soft)}.no-shot{margin:18px 0;padding:22px;border:1px dashed var(--line);border-radius:var(--radius);color:var(--ink-soft);background:var(--surface)}.thread{margin:22px 0;display:flex;flex-direction:column;gap:14px}.comment{border-inline-start:2px solid var(--line);padding-inline-start:12px}.comment-head{display:flex;gap:8px;align-items:baseline;font-size:13px}.comment-head b{font-weight:600}.comment p{margin:3px 0 0;white-space:pre-wrap}.agent{font:600 10px/1 var(--sans);text-transform:uppercase;letter-spacing:.05em;padding:2px 5px;border-radius:3px;background:var(--review);color:var(--surface)}.block{margin:22px 0 0;border-top:1px solid var(--line);padding-top:14px}.block h2{font:600 11px/1 var(--sans);text-transform:uppercase;letter-spacing:.06em;color:var(--ink-faint);margin:0 0 10px}.kv{display:grid;grid-template-columns:max-content 1fr;gap:4px 14px;font-size:13px}.kv dt{color:var(--ink-soft)}.kv dd{margin:0;font-family:var(--mono);font-size:12.5px;overflow-wrap:anywhere}.warn{color:var(--warn)}.actions{display:flex;gap:8px;margin:18px 0 0;flex-wrap:wrap}.btn{font:500 13px/1 var(--sans);padding:8px 12px;border:1px solid var(--line-strong);border-radius:var(--radius);background:var(--surface);cursor:pointer}.btn:hover{border-color:var(--ink-faint)}.btn-primary{background:var(--accent);border-color:transparent;color:var(--on-accent)}.btn-primary:hover{filter:brightness(1.08)}.empty{padding:48px 26px;color:var(--ink-soft);max-width:46ch}.empty h2{font:600 16px/1.4 var(--sans);color:var(--ink);margin:0 0 6px}.gate{min-height:100vh;display:grid;place-items:center;padding:24px}.card{width:100%;max-width:360px;background:var(--surface);border:1px solid var(--line);border-radius:10px;padding:26px}.card h1{font:600 18px/1.3 var(--sans);margin:0 0 4px}.card p.sub{margin:0 0 18px;color:var(--ink-soft);font-size:13px}.field{display:block;margin-bottom:12px}.field span{display:block;font-size:12.5px;color:var(--ink-soft);margin-bottom:4px}.field input,.field textarea{font:inherit;width:100%;padding:8px 10px;border:1px solid var(--line-strong);border-radius:var(--radius);background:var(--bg);color:inherit}.field textarea{resize:vertical;min-height:60px}.field input:focus-visible,.field textarea:focus-visible{outline:2px solid var(--accent);outline-offset:1px}.composer{margin:18px 0 0;max-width:480px}.composer .field{margin-bottom:8px}.composer .btn-primary{padding:8px 14px}.card .btn-primary{width:100%;padding:10px}.err{margin:0 0 14px;padding:9px 11px;border-radius:var(--radius);background:color-mix(in srgb,var(--warn) 12%,transparent);color:var(--warn);font-size:13px}.foot{flex:none;border-top:1px solid var(--line);padding:10px 16px;font:12px/1.4 var(--mono);color:var(--ink-faint);display:flex;gap:12px;flex-wrap:wrap}.carryover{display:block;width:100%;text-align:start;flex:none;border:0;border-bottom:1px solid color-mix(in srgb,var(--warn) 35%,transparent);background:color-mix(in srgb,var(--warn) 12%,transparent);color:var(--warn);font:inherit;padding:9px 16px;cursor:pointer}.carryover:hover{background:color-mix(in srgb,var(--warn) 20%,transparent)}.links{flex:1;display:grid;grid-template-columns:1fr minmax(300px,380px);gap:0;min-height:0;overflow:hidden}@media(max-width:900px){.links{grid-template-columns:1fr;overflow-y:auto}}.links-list{padding:22px 26px;overflow-y:auto;min-height:0}.links-title{font:600 19px/1.3 var(--sans);margin:0 0 16px;letter-spacing:-.01em}.links-side{border-inline-start:1px solid var(--line);background:var(--surface);padding:22px;overflow-y:auto;min-height:0;display:flex;flex-direction:column;gap:16px}.links-side .card{max-width:none;padding:20px}.links-side .card h2{font:600 15px/1.3 var(--sans);margin:0 0 4px}.links-side .card p.sub{margin:0 0 14px;color:var(--ink-soft);font-size:13px}.link-table{width:100%;border-collapse:collapse;font-size:13px}.link-table th{text-align:start;font:600 11px/1 var(--sans);text-transform:uppercase;letter-spacing:.05em;color:var(--ink-faint);padding:0 10px 8px 0;border-bottom:1px solid var(--line)}.link-table td{padding:10px 10px 10px 0;border-bottom:1px solid var(--line-soft);vertical-align:top}.link-table tr.link-dead{color:var(--ink-faint)}.link-round{display:inline-block;margin-inline-start:6px;font-size:11px;color:var(--ink-faint);border:1px solid var(--line);border-radius:999px;padding:1px 7px}.minted{border-color:var(--accent)}.token-box{display:flex;align-items:center;gap:8px;padding:9px 11px;border:1px solid var(--line);border-radius:var(--radius);background:var(--bg)}.token-box code{flex:1;font:12.5px/1.4 var(--mono);overflow-wrap:anywhere}.field select{font:inherit;width:100%;padding:8px 10px;border:1px solid var(--line-strong);border-radius:var(--radius);background:var(--bg);color:inherit}.sites{max-width:720px;margin:0 auto;padding:24px 20px 64px;display:flex;flex-direction:column;gap:28px}.sites h2{font-size:15px;margin:0 0 12px}.sites h3{font-size:13px;margin:20px 0 8px;color:var(--ink-soft)}.sites form{display:flex;flex-direction:column;gap:14px}.sites label{display:flex;flex-direction:column;gap:5px;font-size:13px;color:var(--ink-soft)}.sites input{font:inherit;padding:8px 10px;border:1px solid var(--line-strong);border-radius:var(--radius);background:var(--bg);color:inherit}.sites input:focus-visible{outline:2px solid var(--accent);outline-offset:1px}.sites small{color:var(--ink-faint);font-size:12px;line-height:1.5}.sites small code{font:11.5px/1 var(--mono)}.sites button[type=submit]{align-self:flex-start;font:inherit;padding:8px 14px;border:1px solid var(--accent);border-radius:var(--radius);background:var(--accent);color:var(--on-accent);cursor:pointer}.sites button[type=submit]:disabled{opacity:.45;cursor:default}.sites .error{color:var(--warn);font-size:13px;margin:0}.site-add,.site-made,.site-list{border:1px solid var(--line);border-radius:var(--radius);background:var(--surface);padding:18px 20px}.site-made{border-color:var(--accent)}.site-made p{font-size:13px;color:var(--ink-soft);margin:0 0 10px}.site-made pre{margin:0 0 8px;padding:11px 12px;border:1px solid var(--line);border-radius:var(--radius);background:var(--bg);overflow-x:auto}.site-made pre code{font:12.5px/1.5 var(--mono);white-space:pre}.site-made form{flex-direction:row;align-items:center;gap:8px;margin-top:10px}.site-made form input{flex:1}.site-made form button{font:inherit;padding:8px 12px;border:1px solid var(--line);border-radius:var(--radius);background:var(--bg);color:inherit;cursor:pointer}.origins{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:6px}.origins li code{font:11.5px/1 var(--mono);padding:4px 8px;border:1px solid var(--line);border-radius:999px;background:var(--bg)}.site-list ul{list-style:none;margin:0;padding:0}.site-list li{display:flex;align-items:baseline;gap:10px;padding:9px 0;border-bottom:1px solid var(--line-soft);font-size:13px}.site-list li:last-child{border-bottom:0}.site-list li code{font:11.5px/1 var(--mono);color:var(--ink-faint)}.site-list li span{margin-left:auto;color:var(--ink-faint);font-size:12px}.setup{max-width:460px;margin:0 auto;padding:56px 24px 64px}.setup h1{font-size:20px;margin:0 0 8px}.setup-lede{color:var(--ink-soft);font-size:13px;line-height:1.6;margin:0 0 24px}.setup form{display:flex;flex-direction:column;gap:16px}.setup label{display:flex;flex-direction:column;gap:5px;font-size:13px;color:var(--ink-soft)}.setup-opt{color:var(--ink-faint);font-weight:400}.setup input{font:inherit;padding:9px 11px;border:1px solid var(--line-strong);border-radius:var(--radius);background:var(--bg);color:inherit}.setup input:focus-visible{outline:2px solid var(--accent);outline-offset:1px}.setup small{color:var(--ink-faint);font-size:12px;line-height:1.5}.setup button[type=submit],.setup-actions button:not(.linkish){font:inherit;padding:9px 14px;border:1px solid var(--accent);border-radius:var(--radius);background:var(--accent);color:var(--on-accent);cursor:pointer}.setup button[type=submit]:disabled{opacity:.45;cursor:default}.setup .error{color:var(--warn);font-size:13px;margin:0}.setup pre{margin:0 0 12px;padding:11px 12px;border:1px solid var(--line);border-radius:var(--radius);background:var(--bg);overflow-x:auto}.setup pre code{font:12.5px/1.5 var(--mono);white-space:pre}.setup-actions{display:flex;align-items:center;gap:12px}.setup-note{color:var(--ink-faint);font-size:12.5px;line-height:1.6;margin:24px 0 0}.site-audience{display:flex;flex-direction:column;gap:8px;margin:0 0 12px}.site-audience label{display:flex;gap:9px;align-items:baseline;font-size:12.5px;color:var(--ink-soft);line-height:1.5;cursor:pointer}.site-audience input{accent-color:var(--accent)}.site-audience strong{color:var(--ink);font-weight:600}
@@ -0,0 +1 @@
1
+ (function(){const n=document.createElement("link").relList;if(n&&n.supports&&n.supports("modulepreload"))return;for(const i of document.querySelectorAll('link[rel="modulepreload"]'))o(i);new MutationObserver(i=>{for(const s of i)if(s.type==="childList")for(const a of s.addedNodes)a.tagName==="LINK"&&a.rel==="modulepreload"&&o(a)}).observe(document,{childList:!0,subtree:!0});function r(i){const s={};return i.integrity&&(s.integrity=i.integrity),i.referrerPolicy&&(s.referrerPolicy=i.referrerPolicy),i.crossOrigin==="use-credentials"?s.credentials="include":i.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function o(i){if(i.ep)return;i.ep=!0;const s=r(i);fetch(i.href,s)}})();var ee,C,Pe,U,pe,xe,Ie,te,V,F,Ee,ae,ie,se,Q={},X=[],Be=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,ne=Array.isArray;function D(e,n){for(var r in n)e[r]=n[r];return e}function ce(e){e&&e.parentNode&&e.parentNode.removeChild(e)}function We(e,n,r){var o,i,s,a={};for(s in n)s=="key"?o=n[s]:s=="ref"?i=n[s]:a[s]=n[s];if(arguments.length>2&&(a.children=arguments.length>3?ee.call(arguments,2):r),typeof e=="function"&&e.defaultProps!=null)for(s in e.defaultProps)a[s]===void 0&&(a[s]=e.defaultProps[s]);return K(e,a,o,i,null)}function K(e,n,r,o,i){var s={type:e,props:n,key:r,ref:o,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:i??++Pe,__i:-1,__u:0};return i==null&&C.vnode!=null&&C.vnode(s),s}function N(e){return e.children}function J(e,n){this.props=e,this.context=n}function q(e,n){if(n==null)return e.__?q(e.__,e.__i+1):null;for(var r;n<e.__k.length;n++)if((r=e.__k[n])!=null&&r.__e!=null)return r.__e;return typeof e.type=="function"?q(e):null}function Ge(e){if(e.__P&&e.__d){var n=e.__v,r=n.__e,o=[],i=[],s=D({},n);s.__v=n.__v+1,C.vnode&&C.vnode(s),de(e.__P,s,n,e.__n,e.__P.namespaceURI,32&n.__u?[r]:null,o,r??q(n),!!(32&n.__u),i),s.__v=n.__v,s.__.__k[s.__i]=s,Le(o,s,i),n.__e=n.__=null,s.__e!=r&&je(s)}}function je(e){if((e=e.__)!=null&&e.__c!=null)return e.__e=e.__c.base=null,e.__k.some(function(n){if(n!=null&&n.__e!=null)return e.__e=e.__c.base=n.__e}),je(e)}function me(e){(!e.__d&&(e.__d=!0)&&U.push(e)&&!Z.__r++||pe!=C.debounceRendering)&&((pe=C.debounceRendering)||xe)(Z)}function Z(){try{for(var e,n=1;U.length;)U.length>n&&U.sort(Ie),e=U.shift(),n=U.length,Ge(e)}finally{U.length=Z.__r=0}}function Ne(e,n,r,o,i,s,a,c,_,d,p){var k,l,h,m,y,b,f=o&&o.__k||X,g=n.length;for(_=ze(r,n,f,_,g),k=0;k<g;k++)(h=r.__k[k])!=null&&(l=h.__i!=-1&&f[h.__i]||Q,h.__i=k,b=de(e,h,l,i,s,a,c,_,d,p),m=h.__e,h.ref&&l.ref!=h.ref&&(l.ref&&ue(l.ref,null,h),p.push(h.ref,h.__c||m,h)),y==null&&m!=null&&(y=m),4&h.__u?(_=Re(h,_,e),l.__e&&(l.__e=null)):typeof h.type=="function"&&b!==void 0?_=b:m&&(_=m.nextSibling),h.__u&=-7);return r.__e=y,_}function ze(e,n,r,o,i){var s,a,c,_,d,p=r.length,k=p,l=0;for(e.__k=new Array(i),s=0;s<i;s++)(a=n[s])!=null&&typeof a!="boolean"&&typeof a!="function"?(typeof a=="string"||typeof a=="number"||typeof a=="bigint"||a.constructor==String?a=e.__k[s]=K(null,a,null,null,null):ne(a)?a=e.__k[s]=K(N,{children:a},null,null,null):a.constructor===void 0&&a.__b>0?a=e.__k[s]=K(a.type,a.props,a.key,a.ref?a.ref:null,a.__v):e.__k[s]=a,_=s+l,a.__=e,a.__b=e.__b+1,c=null,(d=a.__i=Ve(a,r,_,k))!=-1&&(k--,(c=r[d])&&(c.__u|=2)),c==null||c.__v==null?(d==-1&&(i>p?l--:i<p&&l++),typeof a.type!="function"&&(a.__u|=4)):d!=_&&(d==_-1?l--:d==_+1?l++:(d>_?l--:l++,a.__u|=4))):e.__k[s]=null;if(k)for(s=0;s<p;s++)(c=r[s])!=null&&(2&c.__u)==0&&(c.__e==o&&(o=q(c)),qe(c,c));return o}function Re(e,n,r){var o,i;if(typeof e.type=="function"){for(o=e.__k,i=0;o&&i<o.length;i++)o[i]&&(o[i].__=e,n=Re(o[i],n,r));return n}e.__e!=n&&(n&&e.type&&!n.parentNode&&(n=q(e)),n=r.insertBefore(e.__e,n||null));do n=n&&n.nextSibling;while(n!=null&&n.nodeType==8);return n}function Ve(e,n,r,o){var i,s,a,c=e.key,_=e.type,d=n[r],p=d!=null&&(2&d.__u)==0;if(d===null&&c==null||p&&c==d.key&&_==d.type)return r;if(o>(p?1:0)){for(i=r-1,s=r+1;i>=0||s<n.length;)if((d=n[a=i>=0?i--:s++])!=null&&(2&d.__u)==0&&c==d.key&&_==d.type)return a}return-1}function fe(e,n,r){n[0]=="-"?e.setProperty(n,r??""):e[n]=r==null?"":typeof r!="number"||Be.test(n)?r:r+"px"}function G(e,n,r,o,i){var s,a;e:if(n=="style")if(typeof r=="string")e.style.cssText=r;else{if(typeof o=="string"&&(e.style.cssText=o=""),o)for(n in o)r&&n in r||fe(e.style,n,"");if(r)for(n in r)o&&r[n]==o[n]||fe(e.style,n,r[n])}else if(n[0]=="o"&&n[1]=="n")s=n!=(n=n.replace(Ee,"$1")),a=n.toLowerCase(),n=a in e||n=="onFocusOut"||n=="onFocusIn"?a.slice(2):n.slice(2),e.l||(e.l={}),e.l[n+s]=r,r?o?r[F]=o[F]:(r[F]=ae,e.addEventListener(n,s?se:ie,s)):e.removeEventListener(n,s?se:ie,s);else{if(i=="http://www.w3.org/2000/svg")n=n.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if(n!="width"&&n!="height"&&n!="href"&&n!="list"&&n!="form"&&n!="tabIndex"&&n!="download"&&n!="rowSpan"&&n!="colSpan"&&n!="role"&&n!="popover"&&n in e)try{e[n]=r??"";break e}catch{}typeof r=="function"||(r==null||r===!1&&n[4]!="-"?e.removeAttribute(n):e.setAttribute(n,n=="popover"&&r==1?"":r))}}function ve(e){return function(n){if(this.l){var r=this.l[n.type+e];if(n[V]==null)n[V]=ae++;else if(n[V]<r[F])return;return r(C.event?C.event(n):n)}}}function de(e,n,r,o,i,s,a,c,_,d){var p,k,l,h,m,y,b,f,g,T,R,v,u,S,A,$,j=n.type;if(n.constructor!==void 0)return null;128&r.__u&&(_=!!(32&r.__u),s=[c=n.__e=r.__e]),(p=C.__b)&&p(n);e:if(typeof j=="function"){k=a.length;try{if(g=n.props,T=j.prototype&&j.prototype.render,R=(p=j.contextType)&&o[p.__c],v=p?R?R.props.value:p.__:o,r.__c?f=(l=n.__c=r.__c).__=l.__E:(T?n.__c=l=new j(g,v):(n.__c=l=new J(g,v),l.constructor=j,l.render=Je),R&&R.sub(l),l.state||(l.state={}),l.__n=o,h=l.__d=!0,l.__h=[],l._sb=[]),T&&l.__s==null&&(l.__s=l.state),T&&j.getDerivedStateFromProps!=null&&(l.__s==l.state&&(l.__s=D({},l.__s)),D(l.__s,j.getDerivedStateFromProps(g,l.__s))),m=l.props,y=l.state,l.__v=n,h)T&&j.getDerivedStateFromProps==null&&l.componentWillMount!=null&&l.componentWillMount(),T&&l.componentDidMount!=null&&l.__h.push(l.componentDidMount);else{if(T&&j.getDerivedStateFromProps==null&&g!==m&&l.componentWillReceiveProps!=null&&l.componentWillReceiveProps(g,v),n.__v==r.__v||!l.__e&&l.shouldComponentUpdate!=null&&l.shouldComponentUpdate(g,l.__s,v)===!1){n.__v!=r.__v&&(l.props=g,l.state=l.__s,l.__d=!1),n.__e=r.__e,n.__k=r.__k,n.__k.some(function(O){O&&(O.__=n)}),X.push.apply(l.__h,l._sb),l._sb=[],l.__h.length&&a.push(l),c=q(r);break e}l.componentWillUpdate!=null&&l.componentWillUpdate(g,l.__s,v),T&&l.componentDidUpdate!=null&&l.__h.push(function(){l.componentDidUpdate(m,y,b)})}if(l.context=v,l.props=g,l.__P=e,l.__e=!1,u=C.__r,S=0,T)l.state=l.__s,l.__d=!1,u&&u(n),p=l.render(l.props,l.state,l.context),X.push.apply(l.__h,l._sb),l._sb=[];else do l.__d=!1,u&&u(n),p=l.render(l.props,l.state,l.context),l.state=l.__s;while(l.__d&&++S<25);l.state=l.__s,l.getChildContext!=null&&(o=D(D({},o),l.getChildContext())),T&&!h&&l.getSnapshotBeforeUpdate!=null&&(b=l.getSnapshotBeforeUpdate(m,y)),A=p!=null&&p.type===N&&p.key==null?Ue(p.props.children):p,c=Ne(e,ne(A)?A:[A],n,r,o,i,s,a,c,_,d),l.base=n.__e,n.__u&=-161,l.__h.length&&a.push(l),f&&(l.__E=l.__=null)}catch(O){if(a.length=k,n.__v=null,_||s!=null){if(O.then){for(n.__u|=_?160:128;c&&c.nodeType==8&&c.nextSibling;)c=c.nextSibling;s!=null&&(s[s.indexOf(c)]=null),n.__e=c}else if(s!=null)for($=s.length;$--;)ce(s[$])}else n.__e=r.__e;n.__k==null&&(n.__k=r.__k||[]),O.then||De(n),C.__e(O,n,r)}}else s==null&&n.__v==r.__v?(n.__k=r.__k,n.__e=r.__e):c=n.__e=Ke(r.__e,n,r,o,i,s,a,_,d);return(p=C.diffed)&&p(n),128&n.__u?void 0:c}function De(e){e&&(e.__c&&(e.__c.__e=!0),e.__k&&e.__k.some(De))}function Le(e,n,r){for(var o=0;o<r.length;o++)ue(r[o],r[++o],r[++o]);C.__c&&C.__c(n,e),e.some(function(i){try{e=i.__h,i.__h=[],e.some(function(s){s.call(i)})}catch(s){C.__e(s,i.__v)}})}function Ue(e){return typeof e!="object"||e==null||e.__b>0?e:ne(e)?e.map(Ue):e.constructor!==void 0?null:D({},e)}function Ke(e,n,r,o,i,s,a,c,_){var d,p,k,l,h,m,y,b=r.props||Q,f=n.props,g=n.type;if(g=="svg"?i="http://www.w3.org/2000/svg":g=="math"?i="http://www.w3.org/1998/Math/MathML":i||(i="http://www.w3.org/1999/xhtml"),s!=null){for(d=0;d<s.length;d++)if((h=s[d])&&"setAttribute"in h==!!g&&(g?h.localName==g:h.nodeType==3)){e=h,s[d]=null;break}}if(e==null){if(g==null)return document.createTextNode(f);e=document.createElementNS(i,g,f.is&&f),c&&(C.__m&&C.__m(n,s),c=!1),s=null}if(g==null)b===f||c&&e.data==f||(e.data=f);else{if(s=g=="textarea"&&f.defaultValue!=null?null:s&&ee.call(e.childNodes),!c&&s!=null)for(b={},d=0;d<e.attributes.length;d++)b[(h=e.attributes[d]).name]=h.value;for(d in b)h=b[d],d=="dangerouslySetInnerHTML"?k=h:d=="children"||d in f||d=="value"&&"defaultValue"in f||d=="checked"&&"defaultChecked"in f||G(e,d,null,h,i);for(d in f)h=f[d],d=="children"?l=h:d=="dangerouslySetInnerHTML"?p=h:d=="value"?m=h:d=="checked"?y=h:c&&typeof h!="function"||b[d]===h||G(e,d,h,b[d],i);if(p)c||k&&(p.__html==k.__html||p.__html==e.innerHTML)||(e.innerHTML=p.__html),n.__k=[];else if(k&&(e.innerHTML=""),Ne(n.type=="template"?e.content:e,ne(l)?l:[l],n,r,o,g=="foreignObject"?"http://www.w3.org/1999/xhtml":i,s,a,s?s[0]:r.__k&&q(r,0),c,_),s!=null)for(d=s.length;d--;)ce(s[d]);c&&g!="textarea"||(d="value",g=="progress"&&m==null?e.removeAttribute("value"):m!=null&&(m!==e[d]||g=="progress"&&!m||g=="option"&&m!=b[d])&&G(e,d,m,b[d],i),d="checked",y!=null&&y!=e[d]&&G(e,d,y,b[d],i))}return e}function ue(e,n,r){try{if(typeof e=="function"){var o=typeof e.__u=="function";o&&e.__u(),o&&n==null||(e.__u=e(n))}else e.current=n}catch(i){C.__e(i,r)}}function qe(e,n,r){var o,i;if(C.unmount&&C.unmount(e),(o=e.ref)&&(o.current&&o.current!=e.__e||ue(o,null,n)),(o=e.__c)!=null){if(o.componentWillUnmount)try{o.componentWillUnmount()}catch(s){C.__e(s,n)}o.base=o.__P=o.__n=null}if(o=e.__k)for(i=0;i<o.length;i++)o[i]&&qe(o[i],n,r||typeof e.type!="function");r||ce(e.__e),e.__c=e.__=e.__e=void 0}function Je(e,n,r){return this.constructor(e,r)}function Ye(e,n,r){var o,i,s,a;n==document&&(n=document.documentElement),C.__&&C.__(e,n),i=(o=!1)?null:n.__k,s=[],a=[],de(n,e=n.__k=We(N,null,[e]),i||Q,Q,n.namespaceURI,i?null:n.firstChild?ee.call(n.childNodes):null,s,i?i.__e:n.firstChild,o,a),Le(s,e,a),e.props.children=null}ee=X.slice,C={__e:function(e,n,r,o){for(var i,s,a;n=n.__;)if((i=n.__c)&&!i.__)try{if((s=i.constructor)&&s.getDerivedStateFromError!=null&&(i.setState(s.getDerivedStateFromError(e)),a=i.__d),i.componentDidCatch!=null&&(i.componentDidCatch(e,o||{}),a=i.__d),a)return i.__E=i}catch(c){e=c}throw e}},Pe=0,J.prototype.setState=function(e,n){var r;r=this.__s!=null&&this.__s!=this.state?this.__s:this.__s=D({},this.state),typeof e=="function"&&(e=e(D({},r),this.props)),e&&D(r,e),e!=null&&this.__v&&(n&&this._sb.push(n),me(this))},J.prototype.forceUpdate=function(e){this.__v&&(this.__e=!0,e&&this.__h.push(e),me(this))},J.prototype.render=N,U=[],xe=typeof Promise=="function"?Promise.prototype.then.bind(Promise.resolve()):setTimeout,Ie=function(e,n){return e.__v.__b-n.__v.__b},Z.__r=0,te=Math.random().toString(8),V="__d"+te,F="__a"+te,Ee=/(PointerCapture)$|Capture$/i,ae=0,ie=ve(!1),se=ve(!0);var Qe=0;function t(e,n,r,o,i,s){n||(n={});var a,c,_=n;if("ref"in _)for(c in _={},n)c=="ref"?a=n[c]:_[c]=n[c];var d={type:e,props:_,key:r,ref:a,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:--Qe,__i:-1,__u:0,__source:i,__self:s};if(typeof e=="function"&&(a=e.defaultProps))for(c in a)_[c]===void 0&&(_[c]=a[c]);return C.vnode&&C.vnode(d),d}var B,P,re,ge,W=0,Oe=[],x=C,ye=x.__b,be=x.__r,we=x.diffed,ke=x.__c,Se=x.unmount,Ce=x.__;function _e(e,n){x.__h&&x.__h(P,e,W||n),W=0;var r=P.__H||(P.__H={__:[],__h:[]});return e>=r.__.length&&r.__.push({}),r.__[e]}function w(e){return W=1,Xe(Fe,e)}function Xe(e,n,r){var o=_e(B++,2);if(o.t=e,!o.__c&&(o.__=[Fe(void 0,n),function(c){var _=o.__N?o.__N[0]:o.__[0],d=o.t(_,c);_!==d&&(o.__N=[d,o.__[1]],o.__c.setState({}))}],o.__c=P,!P.__f)){var i=function(c,_,d){if(!o.__c.__H)return!0;var p=!1,k=o.__c.props!==c;if(o.__c.__H.__.some(function(h){if(h.__N){p=!0;var m=h.__[0];h.__=h.__N,h.__N=void 0,m!==h.__[0]&&(k=!0)}}),s){var l=s.call(this,c,_,d);return p?l||k:l}return!p||k};P.__f=!0;var s=P.shouldComponentUpdate,a=P.componentWillUpdate;P.componentWillUpdate=function(c,_,d){if(this.__e){var p=s;s=void 0,i(c,_,d),s=p}a&&a.call(this,c,_,d)},P.shouldComponentUpdate=i}return o.__N||o.__}function M(e,n){var r=_e(B++,3);!x.__s&&Me(r.__H,n)&&(r.__=e,r.u=n,P.__H.__h.push(r))}function Ze(e){return W=5,he(function(){return{current:e}},[])}function he(e,n){var r=_e(B++,7);return Me(r.__H,n)&&(r.__=e(),r.__H=n,r.__h=e),r.__}function He(e,n){return W=8,he(function(){return e},n)}function en(){for(var e;e=Oe.shift();){var n=e.__H;if(e.__P&&n)try{n.__h.some(Y),n.__h.some(oe),n.__h=[]}catch(r){n.__h=[],x.__e(r,e.__v)}}}x.__b=function(e){P=null,ye&&ye(e)},x.__=function(e,n){e&&n.__k&&n.__k.__m&&(e.__m=n.__k.__m),Ce&&Ce(e,n)},x.__r=function(e){be&&be(e),B=0;var n=(P=e.__c).__H;n&&(re===P?(n.__h=[],P.__h=[],n.__.some(function(r){r.__N&&(r.__=r.__N),r.u=r.__N=void 0})):(n.__h.some(Y),n.__h.some(oe),n.__h=[],B=0)),re=P},x.diffed=function(e){we&&we(e);var n=e.__c;n&&n.__H&&(n.__H.__h.length&&(Oe.push(n)!==1&&ge===x.requestAnimationFrame||((ge=x.requestAnimationFrame)||nn)(en)),n.__H.__.some(function(r){r.u&&(r.__H=r.u,r.u=void 0)})),re=P=null},x.__c=function(e,n){n.some(function(r){try{r.__h.some(Y),r.__h=r.__h.filter(function(o){return!o.__||oe(o)})}catch(o){n.some(function(i){i.__h&&(i.__h=[])}),n=[],x.__e(o,r.__v)}}),ke&&ke(e,n)},x.unmount=function(e){Se&&Se(e);var n,r=e.__c;r&&r.__H&&(r.__H.__.some(function(o){try{Y(o)}catch(i){n=i}}),r.__H=void 0,n&&x.__e(n,r.__v))};var $e=typeof requestAnimationFrame=="function";function nn(e){var n,r=function(){clearTimeout(o),$e&&cancelAnimationFrame(n),setTimeout(e)},o=setTimeout(r,35);$e&&(n=requestAnimationFrame(r))}function Y(e){var n=P,r=e.__c;typeof r=="function"&&(e.__c=void 0,r()),P=n}function oe(e){var n=P;e.__c=e.__(),P=n}function Me(e,n){return!e||e.length!==n.length||n.some(function(r,o){return r!==e[o]})}function Fe(e,n){return typeof n=="function"?n(e):n}const tn={csrf:"snag_csrf"},rn=tn.csrf,sn={csrf:"x-snagset-csrf"};class L extends Error{status;code;constructor(n,r){super(r.message),this.status=n,this.code=r.code}}function on(){for(const e of document.cookie.split(";")){const n=e.indexOf("=");if(n>0&&e.slice(0,n).trim()===rn)return e.slice(n+1).trim()}return""}async function E(e,n,r){const o=await fetch(n,{method:e,credentials:"same-origin",headers:{...r===void 0?{}:{"content-type":"application/json"},...e==="GET"?{}:{[sn.csrf]:on()}},...r===void 0?{}:{body:JSON.stringify(r)}});if(o.status===204)return;const i=await o.json().catch(()=>null);if(!o.ok){const s=i?.error;throw new L(o.status,s??{code:"unknown",message:`Request failed (${o.status}).`})}return i}const I={me:()=>E("GET","/api/v1/me"),setup:e=>E("POST","/api/v1/setup",e),login:(e,n)=>E("POST","/auth/login",{email:e,password:n}),logout:()=>E("POST","/auth/logout"),threads:(e,n={})=>{const r=new URLSearchParams;n.status&&r.set("status",n.status),n.route&&r.set("route",n.route),n.round&&r.set("round",String(n.round)),n.q&&r.set("q",n.q),n.since&&r.set("since",n.since);const o=r.toString();return E("GET",`/api/v1/projects/${encodeURIComponent(e)}/threads${o?`?${o}`:""}`)},createProject:(e,n)=>E("POST","/api/v1/projects",{name:e,origins:n}),setAudience:(e,n)=>E("PATCH",`/api/v1/projects/${encodeURIComponent(e)}`,{writeMode:n}),origins:e=>E("GET",`/api/v1/projects/${encodeURIComponent(e)}/origins`),addOrigin:(e,n)=>E("POST",`/api/v1/projects/${encodeURIComponent(e)}/origins`,{origin:n}),rounds:e=>E("GET",`/api/v1/projects/${encodeURIComponent(e)}/rounds`),createRound:(e,n)=>E("POST",`/api/v1/projects/${encodeURIComponent(e)}/rounds`,{name:n}),setStatus:(e,n,r)=>E("PATCH",`/api/v1/projects/${encodeURIComponent(e)}/threads/${encodeURIComponent(n)}`,{status:r}),addComment:(e,n)=>E("POST",`/api/v1/threads/${encodeURIComponent(e)}/comments`,{id:crypto.randomUUID(),body:n}),listLinks:e=>E("GET",`/api/v1/projects/${encodeURIComponent(e)}/review-links`),mintLink:(e,n)=>E("POST",`/api/v1/projects/${encodeURIComponent(e)}/review-links`,n),revokeLink:e=>E("DELETE",`/api/v1/review-links/${encodeURIComponent(e)}`)};function Te(e){const n=new Date(e),r=Math.round((Date.now()-n.getTime())/6e4);return r<1?"just now":r<60?`${r}m ago`:r<1440?`${Math.round(r/60)}h ago`:n.toLocaleDateString(void 0,{day:"numeric",month:"short"})}function ln({context:e}){const n=e?.capture,r=e?.viewport,i=[["Viewport",r?.w?`${r.w} × ${r.h}`:null],["Browser",e?.browser??e?.ua??null],["Platform",e?.os??e?.platform??null],["Device pixel ratio",e?.dpr??null]].filter(([,c])=>c!=null&&c!==""),s=n?.category&&n.category!=="ok"&&n.category!=="full";return!i.length&&!n?null:t("section",{class:"block",children:[t("h2",{children:["Capture",t("button",{type:"button",class:"linkish",style:"float:right;font-size:12px",onClick:()=>{navigator.clipboard?.writeText(JSON.stringify(e,null,2))},children:"Copy environment"})]}),i.length>0&&t("dl",{class:"kv",children:i.map(([c,_])=>t(N,{children:[t("dt",{children:c}),t("dd",{children:String(_)})]}))}),s&&t("p",{class:"warn",style:"margin:10px 0 0",children:[t("b",{children:n.category}),n.reasons?.length?` — ${n.reasons.join("; ")}`:""]}),n?.blindSpots?.length?t("p",{class:"warn",style:"margin:6px 0 0",children:[n.blindSpots.length," blind spot",n.blindSpots.length===1?"":"s",": ",n.blindSpots.join("; ")]}):null,n?.droppedCategories?.length?t("p",{class:"warn",style:"margin:6px 0 0",children:["Dropped: ",n.droppedCategories.join(", ")]}):null]})}function an({onReply:e}){const[n,r]=w(""),[o,i]=w(!1),[s,a]=w("");return t("form",{class:"composer",onSubmit:async c=>{c.preventDefault();const _=n.trim();if(!(!_||o)){i(!0),a("");try{await e(_),r("")}catch(d){a(d instanceof L?d.message:"Could not send that reply.")}finally{i(!1)}}},children:[t("label",{class:"field",children:[t("span",{children:"Reply"}),t("textarea",{rows:3,placeholder:"Write a reply…",value:n,disabled:o,onInput:c=>r(c.target.value)})]}),s&&t("p",{class:"err",children:s}),t("button",{class:"btn btn-primary",type:"submit",disabled:o||!n.trim(),children:o?"Sending…":"Reply"})]})}function cn({thread:e,onStatus:n,onReply:r,busy:o}){const i=e.attachments?.find(c=>c.kind==="screenshot")??e.attachments?.[0],s=e.anchor?.label??"",a=e.anchor??{};return t("article",{class:"detail detail-open",children:[t("div",{class:"detail-head",children:[t("span",{class:"key",children:e.key}),t("h1",{children:s||"A comment on this page"}),t("span",{class:`status status-${e.status}`,children:le[e.status]??e.status})]}),t("p",{style:"margin:6px 0 0;color:var(--ink-soft);font-size:13px",children:["Round ",e.roundNumber," · ",e.route||"/"," · left by ",e.createdBy.name||"someone"," ",Te(e.createdAt)]}),i?t("figure",{class:"shot",children:[t("img",{src:i.url,alt:`Screenshot of the page when ${e.key} was left`,width:i.width,height:i.height,loading:"lazy"}),t("figcaption",{children:["captured at ",i.width??"?"," × ",i.height??"?"]})]}):t("div",{class:"no-shot",children:[t("b",{children:"No screenshot for this one."}),t("p",{style:"margin:6px 0 0",children:"Either this instance had no bucket connected when it was left, or the reviewer turned the picture off for this comment. The anchor and the page context below are unaffected."})]}),t("section",{class:"thread",children:[e.comments.length===0&&t("p",{style:"color:var(--ink-soft)",children:"This thread has no readable comments."}),e.comments.map(c=>t("div",{class:"comment",children:[t("div",{class:"comment-head",children:[t("b",{children:c.author.name||"Anonymous"}),c.author.kind==="agent"&&t("span",{class:"agent",children:"agent"}),t("span",{style:"color:var(--ink-faint)",children:Te(c.createdAt)})]}),t("p",{children:c.body??t("i",{style:"color:var(--ink-faint)",children:"deleted"})})]},c.id))]}),t(an,{onReply:r}),t("section",{class:"block",children:[t("h2",{children:"Anchor"}),t("dl",{class:"kv",children:[t("dt",{children:"State"}),t("dd",{children:e.anchorState}),s&&t(N,{children:[t("dt",{children:"Label"}),t("dd",{children:s})]}),a.css&&t(N,{children:[t("dt",{children:"Selector"}),t("dd",{children:String(a.css)})]}),a.domid&&t(N,{children:[t("dt",{children:"DOM id"}),t("dd",{children:String(a.domid)})]}),a.page?.pathname&&t(N,{children:[t("dt",{children:"Path"}),t("dd",{children:String(a.page.pathname)})]})]})]}),t(ln,{context:e.context??{}}),t("div",{class:"actions",children:[e.status!=="resolved"?t("button",{class:"btn btn-primary",disabled:o,onClick:()=>n("resolved"),children:"Mark resolved"}):t("button",{class:"btn",disabled:o,onClick:()=>n("open"),children:"Reopen"}),e.status!=="progress"&&e.status!=="resolved"&&t("button",{class:"btn",disabled:o,onClick:()=>n("progress"),children:"In progress"}),a.page?.origin&&t("a",{class:"btn",href:`${a.page.origin}${a.page.pathname??"/"}?snag_t=${encodeURIComponent(e.key)}`,target:"_blank",rel:"noreferrer noopener",children:"Open on site ↗"})]})]})}function z(e){return e?new Date(e).toLocaleDateString(void 0,{day:"numeric",month:"short",year:"numeric"}):"—"}function dn({uid:e,rounds:n}){const[r,o]=w(null),[i,s]=w(""),[a,c]=w(null),[_,d]=w(null),[p,k]=w(""),[l,h]=w("14"),[m,y]=w(""),[b,f]=w(!1),g=()=>{o(null),I.listLinks(e).then(v=>o(v.data)).catch(v=>s(v instanceof L?v.message:"Could not load the links."))};M(()=>{c(null),s(""),g()},[e]);const T=async v=>{v.preventDefault();const u=p.trim();if(!(!u||b)){f(!0),s("");try{const S=Number(l),A=Number.isFinite(S)&&S>0?new Date(Date.now()+S*864e5).toISOString():void 0,$=await I.mintLink(e,{name:u,...A?{expiresAt:A}:{},...m?{roundId:m}:{}});c($),k(""),h("14"),y(""),g()}catch(S){s(S instanceof L?S.message:"Could not create that link.")}finally{f(!1)}}},R=async v=>{if(confirm(`Revoke "${v.name}"? Every session minted from it is out within 10 s. This cannot be undone — minting a new link is the recovery.`)){d(v.id),s("");try{await I.revokeLink(v.id),c(u=>u?.id===v.id?null:u),g()}catch(u){s(u instanceof L?u.message:"Could not revoke that link.")}finally{d(null)}}};return t("div",{class:"links",children:[t("div",{class:"links-list",children:[t("h1",{class:"links-title",children:"Review links"}),i&&t("p",{class:"err",children:i}),r===null&&t("p",{class:"empty",children:"Loading…"}),r?.length===0&&t("div",{class:"empty",children:[t("h2",{children:"No links yet"}),t("p",{children:"Mint one on the right — once this project needs a link, it is the only way a reviewer gets in."})]}),r&&r.length>0&&t("table",{class:"link-table",children:[t("thead",{children:t("tr",{children:[t("th",{children:"Name"}),t("th",{children:"Created"}),t("th",{children:"Expires"}),t("th",{children:"Last used"}),t("th",{children:"Uses"}),t("th",{})]})}),t("tbody",{children:r.map(v=>{const u=!!v.revokedAt,S=!u&&new Date(v.expiresAt).getTime()<=Date.now(),A=v.roundId?n?.find($=>$.id===v.roundId):null;return t("tr",{class:u||S?"link-dead":"",children:[t("td",{children:[v.name,A&&t("span",{class:"link-round",children:A.name})]}),t("td",{children:z(v.createdAt)}),t("td",{children:u?t("span",{class:"warn",children:["revoked ",z(v.revokedAt)]}):S?t("span",{class:"warn",children:"expired"}):z(v.expiresAt)}),t("td",{children:z(v.lastUsedAt)}),t("td",{children:v.useCount}),t("td",{children:!u&&t("button",{class:"btn",disabled:_===v.id,onClick:()=>void R(v),children:_===v.id?"Revoking…":"Revoke"})})]},v.id)})})]})]}),t("div",{class:"links-side",children:[a&&t("div",{class:"card minted",children:[t("h2",{children:['"',a.name,'" is ready']}),t("p",{class:"sub",children:["This is the only time the token is shown — the list on the left never carries it again. Paste it after the reviewed site's URL, e.g. ",t("code",{children:["https://yoursite.com/page",a.fragment]}),"."]}),t("div",{class:"token-box",children:[t("code",{children:a.fragment}),t("button",{class:"btn",onClick:()=>void navigator.clipboard.writeText(a.fragment).catch(()=>{}),children:"Copy"})]}),t("button",{class:"linkish",style:"margin-top:10px",onClick:()=>c(null),children:"Done"})]}),t("form",{class:"card",onSubmit:T,children:[t("h2",{children:"New link"}),t("label",{class:"field",children:[t("span",{children:"Name"}),t("input",{required:!0,placeholder:"Client review — round 2",value:p,onInput:v=>k(v.target.value)})]}),t("label",{class:"field",children:[t("span",{children:"Expires in (days, up to 90)"}),t("input",{type:"number",min:1,max:90,value:l,onInput:v=>h(v.target.value)})]}),n&&n.length>0&&t("label",{class:"field",children:[t("span",{children:"Pin to a round (optional)"}),t("select",{value:m,onChange:v=>y(v.target.value),children:[t("option",{value:"",children:"Any round"}),n.map(v=>t("option",{value:v.id,children:v.name},v.id))]})]}),t("button",{class:"btn btn-primary",type:"submit",disabled:b||!p.trim(),children:b?"Creating…":"Create link"})]})]})]})}function un({me:e,onAdded:n,origin:r}){const[o,i]=w(""),[s,a]=w(""),[c,_]=w(!1),[d,p]=w(""),[k,l]=w(null);return t("div",{class:"sites",children:[t("section",{class:"site-add",children:[t("h2",{children:"Add a site"}),t("form",{onSubmit:async m=>{if(m.preventDefault(),!c){_(!0),p("");try{const y=await I.createProject(o.trim(),s.trim());l({uid:y.uid,name:y.name,...y.warning?{warning:y.warning}:{}}),i(""),a(""),n(y.uid)}catch(y){p(y instanceof L?y.message:"Something went wrong. Try again.")}finally{_(!1)}}},children:[t("label",{children:["Name",t("input",{value:o,placeholder:"Acme redesign",onInput:m=>i(m.target.value),required:!0})]}),t("label",{children:["Where it runs",t("input",{value:s,placeholder:"https://staging.acme.com, http://localhost:3000",onInput:m=>a(m.target.value)}),t("small",{children:["Comma-separated, with the scheme. Only these can talk to the site — a tag on any other address is ignored. ",t("code",{children:"https://*.acme.com"})," covers subdomains."]})]}),t("button",{type:"submit",disabled:c||!o.trim(),children:c?"Adding…":"Add site"}),d&&t("p",{class:"error",children:d})]})]}),k&&t(_n,{site:k,origin:r}),t("section",{class:"site-list",children:[t("h2",{children:"Your sites"}),t("ul",{children:e.projects.map(m=>t("li",{children:[t("strong",{children:m.name}),t("code",{children:m.uid}),t("span",{children:[m.threads," snag",m.threads===1?"":"s"," · ",m.unresolved," open"]})]},m.uid))})]})]})}function _n({site:e,origin:n}){const[r,o]=w([]),[i,s]=w(""),[a,c]=w(""),[_,d]=w("everyone"),[p,k]=w(""),l=y=>{const b=_;d(y),k(""),I.setAudience(e.uid,y==="everyone"?"open":"link-required").catch(()=>{d(b),k("Could not save — try again.")})},h=He(()=>{I.origins(e.uid).then(y=>o(y.origins)).catch(()=>o([]))},[e.uid]);M(h,[h]);const m=`<script src="${n}/snag.js" data-snag-site="${e.uid}" defer><\/script>`;return t("section",{class:"site-made",children:[t("h2",{children:[e.name," is ready"]}),t("p",{children:"Paste this into the site, immediately before the closing </body> tag."}),t("div",{class:"site-audience",role:"radiogroup","aria-label":"Who sees the toolbar",children:[t("label",{children:[t("input",{type:"radio",name:"audience",checked:_==="everyone",onChange:()=>l("everyone")}),t("span",{children:[t("strong",{children:"Everyone on these addresses"})," — the toolbar just appears, and anyone can comment. For staging. Saved to the server: change it here any time, no re-paste."]})]}),t("label",{children:[t("input",{type:"radio",name:"audience",checked:_==="links",onChange:()=>l("links")}),t("span",{children:[t("strong",{children:"Only people with a review link"})," — visitors see nothing. For production, where the visitors are your client's customers."]})]}),p&&t("p",{class:"error",children:p})]}),t("pre",{children:t("code",{children:m})}),t("button",{class:"linkish",onClick:()=>{navigator.clipboard?.writeText(m)},children:"Copy"}),t("h3",{children:"Allowed origins"}),r.length?t("ul",{class:"origins",children:r.map(y=>t("li",{children:t("code",{children:y})},y))}):t("p",{class:"warn",children:e.warning??"None yet — the tag will load and every request from it will be refused. Add one below."}),t("form",{onSubmit:async y=>{y.preventDefault();const b=i.trim();if(b){c("");try{const f=await I.addOrigin(e.uid,b);o(f.origins),s("")}catch(f){c(f instanceof L?f.message:"Could not add that origin.")}}},children:[t("input",{value:i,placeholder:"https://www.acme.com",onInput:y=>s(y.target.value)}),t("button",{type:"submit",disabled:!i.trim(),children:"Allow"}),a&&t("p",{class:"error",children:a})]})]})}function hn(e,n,r=[]){const o=new Set(r),i=e.filter(s=>!o.has(s.id));for(const s of n){if(o.has(s.id))continue;const a=i.findIndex(c=>c.id===s.id);a===-1?i.push(s):i[a]=s}return i}function pn({token:e,onClaimed:n}){const[r,o]=w(""),[i,s]=w(""),[a,c]=w(""),[_,d]=w(""),[p,k]=w(!1),[l,h]=w(""),[m,y]=w(null);return m?t(mn,{site:m,onContinue:n}):t("div",{class:"setup",children:[t("h1",{children:"Set up Snagset"}),t("p",{class:"setup-lede",children:"This instance has not been claimed yet. The account you make here is the only one, until you add another."}),t("form",{onSubmit:async f=>{if(f.preventDefault(),!p){k(!0),h("");try{const g=await I.setup({token:e,orgName:r.trim()||"My studio",projectName:i.trim(),email:a.trim(),password:_});y(g.project)}catch(g){h(g instanceof L?g.message:"Something went wrong. Try again.")}finally{k(!1)}}},children:[t("label",{children:["Your email",t("input",{type:"email",value:a,autocomplete:"username",required:!0,onInput:f=>c(f.target.value)})]}),t("label",{children:["Password",t("input",{type:"password",value:_,autocomplete:"new-password",required:!0,minLength:12,onInput:f=>d(f.target.value)}),t("small",{children:"At least 12 characters. There is no reset email on a fresh install — keep it."})]}),t("label",{children:["Studio name ",t("span",{class:"setup-opt",children:"optional"}),t("input",{value:r,placeholder:"My studio",onInput:f=>o(f.target.value)})]}),t("label",{children:["First site ",t("span",{class:"setup-opt",children:"optional"}),t("input",{value:i,placeholder:"Acme redesign",onInput:f=>s(f.target.value)})]}),t("button",{type:"submit",disabled:p||!a.trim()||_.length<12,children:p?"Setting up…":"Create my account"}),l&&t("p",{class:"error",children:l})]})]})}function mn({site:e,onContinue:n}){const r=`<script src="${location.origin}/snag.js" data-snag-site="${e.uid}" defer><\/script>`;return t("div",{class:"setup",children:[t("h1",{children:[e.name," is ready"]}),t("p",{class:"setup-lede",children:"Paste this into the site you want reviewed, before the closing </body> tag."}),t("pre",{children:t("code",{children:r})}),t("div",{class:"setup-actions",children:[t("button",{type:"button",class:"linkish",onClick:()=>void navigator.clipboard?.writeText(r),children:"Copy"}),t("button",{type:"button",onClick:n,children:"Open the dashboard"})]}),t("p",{class:"setup-note",children:"The site's address has to be on its allow-list before comments can reach you — add it on the Sites screen. A tag on any other address loads and is ignored."})]})}const fn=["open","progress","review","resolved"],le={open:"Active",progress:"In progress",review:"In review",resolved:"Resolved"};function H(){const e=new URLSearchParams(location.search);return{project:e.get("project")??"",thread:e.get("t")??"",status:e.get("status")??"",q:e.get("q")??"",round:e.get("round")??"",screen:e.get("screen")??"",claim:e.get("claim")??""}}function Ae(e){const n={...H(),...e},r=new URLSearchParams;n.project&&r.set("project",n.project),n.thread&&r.set("t",n.thread),n.status&&r.set("status",n.status),n.q&&r.set("q",n.q),n.round&&r.set("round",n.round),n.screen&&r.set("screen",n.screen);const o=`${location.pathname}${r.toString()?`?${r}`:""}`;history.pushState(null,"",o)}function vn({onIn:e}){const[n,r]=w(""),[o,i]=w(""),[s,a]=w(""),[c,_]=w(!1);return t("div",{class:"gate",children:t("form",{class:"card",onSubmit:async d=>{d.preventDefault(),_(!0),a("");try{await I.login(n,o),e()}catch(p){a(p instanceof L?p.message:"Could not reach the server.")}finally{_(!1)}},children:[t("h1",{children:"Sign in"}),t("p",{class:"sub",children:"The studio side of Snagset. Reviewers do not sign in — they open a link."}),s&&t("p",{class:"err",children:s}),t("label",{class:"field",children:[t("span",{children:"Email"}),t("input",{type:"email",autocomplete:"username",required:!0,value:n,onInput:d=>r(d.target.value)})]}),t("label",{class:"field",children:[t("span",{children:"Password"}),t("input",{type:"password",autocomplete:"current-password",required:!0,value:o,onInput:d=>i(d.target.value)})]}),t("button",{class:"btn btn-primary",disabled:c,children:c?"Signing in…":"Sign in"}),t("p",{class:"sub",style:"margin:14px 0 0",children:["Forgotten it? There is no reset email on a fresh install — set a new one from the machine that runs the server: ",t("code",{children:"snagset passwd you@example.com"})]})]})})}function gn(){const[e,n]=w(null),[r,o]=w("loading"),[i,s]=w(H()),[a,c]=w(null),_=Ze(null),[d,p]=w(!1),[k,l]=w(null),[h,m]=w(null),y=He(async()=>{try{const u=await I.me();n(u),o("in"),!H().project&&u.projects[0]&&(Ae({project:u.projects[0].uid}),s(H()))}catch{o("out")}},[]);M(()=>{y(),fetch("/api/v1/meta").then(S=>S.json()).then(l).catch(()=>{});const u=()=>s(H());return addEventListener("popstate",u),()=>removeEventListener("popstate",u)},[y]);const b=i.project;M(()=>{if(r!=="in"||!b)return;let u=!0;return m(null),I.rounds(b).then(S=>u&&m(S.data)).catch(()=>u&&m([])),()=>{u=!1}},[r,b]);const f=i.round?Number(i.round):h?.[0]?.number??null;M(()=>{if(r!=="in"||!b||f===null)return;let u=!0;return c(null),I.threads(b,{round:f,...i.status?{status:i.status}:{},...i.q?{q:i.q}:{}}).then(S=>{u&&(c(S.data),_.current=S.serverTime)}).catch(()=>u&&c([])),()=>{u=!1}},[r,b,f,i.status,i.q]),M(()=>{if(r!=="in"||!b)return;let u=0;const S=()=>{if(document.hidden||!_.current)return;const A=Date.now();A-u<3e4||(u=A,I.threads(b,{...f===null?{}:{round:f},since:_.current,...i.status?{status:i.status}:{},...i.q?{q:i.q}:{}}).then($=>{_.current=$.serverTime,!(!$.data.length&&!$.deleted?.length)&&c(j=>j&&hn(j,$.data,$.deleted))}).catch(()=>{}))};return document.addEventListener("visibilitychange",S),()=>document.removeEventListener("visibilitychange",S)},[r,b,f,i.status,i.q]);const g=he(()=>a?.find(u=>u.key===i.thread)??null,[a,i.thread]),T=u=>{Ae(u),s(H())};if(r==="loading")return t("div",{class:"empty",children:"Loading…"});if(r==="out"&&i.claim)return t(pn,{token:i.claim,onClaimed:()=>void y()});if(r==="out")return t(vn,{onIn:()=>void y()});const R=async u=>{if(g){p(!0);try{const S=await I.setStatus(b,g.id,u);c(A=>A?.map($=>$.id===S.id?{...$,...S}:$)??A)}finally{p(!1)}}},v=async u=>{if(!g)return;const S=await I.addComment(g.id,u);c(A=>A?.map($=>$.id===g.id?{...$,comments:[...$.comments,S],commentCount:$.commentCount+1}:$)??A)};return t("div",{class:"shell",children:[t("header",{class:"topbar",children:[t("div",{class:"brand",children:["Snagset ",t("span",{children:"studio"})]}),t("select",{value:b,onChange:u=>T({project:u.target.value,thread:""}),children:e.projects.map(u=>t("option",{value:u.uid,children:[u.name," · ",u.unresolved," open"]},u.uid))}),h&&h.length>0&&t("select",{value:String(f??""),onChange:u=>T({round:u.target.value,thread:""}),children:h.map(u=>t("option",{value:String(u.number),children:[u.name,u.closed?" (closed)":""," · ",u.unresolved," open"]},u.id))}),t("button",{class:"linkish",title:"Start a new round. The page goes clean; nothing is deleted.",onClick:async()=>{const u=(h?.[0]?.number??0)+1,S=prompt("Name for the new round",`Round ${u}`);if(S===null)return;const A=await I.createRound(b,S).catch(()=>null);if(!A)return;const $=await I.rounds(b).catch(()=>null);$&&m($.data),T({round:String(A.number),thread:""})},children:"+ Round"}),t("button",{class:"linkish","aria-pressed":i.screen==="links",onClick:()=>T({screen:i.screen==="links"?"":"links",thread:""}),children:"Links"}),t("button",{class:"linkish","aria-pressed":i.screen==="sites",onClick:()=>T({screen:i.screen==="sites"?"":"sites",thread:""}),children:"Sites"}),t("div",{class:"spacer"}),t("span",{class:"who",children:e.user.email}),t("button",{class:"linkish",onClick:async()=>{await I.logout().catch(()=>{}),o("out")},children:"Sign out"})]}),i.screen==="sites"?t(un,{me:e,origin:location.origin,onAdded:async u=>{const S=await I.me().catch(()=>null);S&&n(S),T({project:u,thread:""})}}):i.screen==="links"?t(dn,{uid:b,rounds:h}):t(N,{children:[h&&f!==null&&t(N,{children:h.filter(u=>u.number!==f&&u.unresolved>0).map(u=>t("button",{class:"carryover",onClick:()=>T({round:String(u.number),thread:""}),children:[t("b",{children:[u.unresolved," unresolved"]})," in ",u.name," — still open, not carried over. Go there ↗"]},u.id))}),t("div",{class:"inbox",children:[t("div",{class:"list",children:[t("div",{class:"filters",children:[t("input",{type:"search",placeholder:"Search comments",value:i.q,onInput:u=>T({q:u.target.value})}),fn.map(u=>t("button",{class:"chip","aria-pressed":i.status===u,onClick:()=>T({status:i.status===u?"":u}),children:le[u]},u))]}),t("div",{class:"rows",children:[a===null&&t("p",{class:"empty",children:"Loading…"}),a?.length===0&&t("div",{class:"empty",children:[t("h2",{children:"Nothing here"}),t("p",{children:i.q||i.status?"No comment matches that filter.":"No comments on this project yet. Paste the script tag on the site and click something."})]}),a?.map(u=>t("button",{class:"row","aria-current":u.key===i.thread,onClick:()=>T({thread:u.key}),children:[t("div",{class:"row-top",children:[t("span",{class:"key",children:u.key}),t("span",{class:`status status-${u.status}`,children:le[u.status]})]}),t("p",{class:"row-body",children:u.comments[0]?.body??u.anchor?.label??"(no comment)"}),t("div",{class:"row-meta",children:[t("span",{children:u.route||"/"}),t("span",{children:"·"}),t("span",{children:u.createdBy.name||"someone"}),u.attachments?.length?t("span",{children:"· 📷"}):null]})]},u.id))]})]}),g?t(cn,{thread:g,onStatus:u=>void R(u),onReply:v,busy:d}):t("div",{class:"empty",children:[t("h2",{children:"Pick a comment"}),t("p",{children:"Its screenshot, the thread, the anchor and the page context all open here."})]})]})]}),t("footer",{class:"foot",children:[t("span",{children:[e.org.name," · ",k?.version??"…"]}),k?.commit&&t("span",{children:k.commit.slice(0,8)})]})]})}Ye(t(gn,{}),document.getElementById("app"));
@@ -4,9 +4,10 @@
4
4
  <meta charset="utf-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
6
6
  <meta name="color-scheme" content="light dark" />
7
+ <link rel="icon" href="/mark.svg" type="image/svg+xml" />
7
8
  <title>Snagset</title>
8
- <script type="module" crossorigin src="/assets/index-DfTNjHCK.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-CaPfKhFP.css">
9
+ <script type="module" crossorigin src="/assets/index-DultqpS7.js"></script>
10
+ <link rel="stylesheet" crossorigin href="/assets/index-DsUJ96yc.css">
10
11
  </head>
11
12
  <body>
12
13
  <div id="app"></div>
@@ -0,0 +1,25 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" role="img" aria-label="Snagset">
2
+ <!--
3
+ D78. The pin at rest on a rule: the shipped pin (a circle of r 12 with its
4
+ lower-left quadrant squared — the same construction as
5
+ `border-radius: 50% 50% 50% 2px` in pins.ts) floating 4.3 units above a
6
+ full-bleed rule.
7
+
8
+ Three things are load-bearing and must not be tidied:
9
+ · the pin FLOATS — it has not landed; touching the rule parks it
10
+ · the composition is ASYMMETRIC — 8 units of rule run on past the pin,
11
+ which is what says `page` rather than `underline`
12
+ · the pin's sharp corner and the rule's left end share x 0, the one
13
+ alignment, which reads only because nothing else lines up
14
+
15
+ Stroke weight, colour and file preparation are in scope for a refinement.
16
+ Position, scale and alignment are the composition.
17
+ -->
18
+ <style>
19
+ :root { color-scheme: light dark; }
20
+ path { fill: #181716; stroke: #181716; }
21
+ @media (prefers-color-scheme: dark) { path { fill: #f0eeec; stroke: #f0eeec; } }
22
+ </style>
23
+ <path d="M0 24V12A12 12 0 0 1 12 0a12 12 0 0 1 12 12 12 12 0 0 1-12 12z" stroke="none"/>
24
+ <path d="M0 30h32" fill="none" stroke-width="3.4" stroke-linecap="square"/>
25
+ </svg>