@snagset/server 0.0.3 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/README.md +4 -3
  2. package/dist/app.js +167 -30
  3. package/dist/app.js.map +1 -1
  4. package/dist/bin.js +46 -9
  5. package/dist/bin.js.map +1 -1
  6. package/dist/boot.js +105 -54
  7. package/dist/boot.js.map +1 -1
  8. package/dist/config.generated.js +5 -2
  9. package/dist/config.generated.js.map +1 -1
  10. package/dist/db/connect.js +7 -0
  11. package/dist/db/connect.js.map +1 -1
  12. package/dist/db/migrations/0005_studio_reviewers.sql +45 -0
  13. package/dist/db/migrations/0006_instance_settings.sql +69 -0
  14. package/dist/db/migrations/0007_jira_provider.no-txn.sql +13 -0
  15. package/dist/domain.js +129 -0
  16. package/dist/domain.js.map +1 -0
  17. package/dist/instance/settings.js +54 -0
  18. package/dist/instance/settings.js.map +1 -0
  19. package/dist/integrations/github.js +112 -0
  20. package/dist/integrations/github.js.map +1 -0
  21. package/dist/integrations/inbound.js +88 -0
  22. package/dist/integrations/inbound.js.map +1 -0
  23. package/dist/integrations/jira.js +129 -0
  24. package/dist/integrations/jira.js.map +1 -0
  25. package/dist/integrations/linear.js +111 -0
  26. package/dist/integrations/linear.js.map +1 -0
  27. package/dist/integrations/outbox.js +305 -0
  28. package/dist/integrations/outbox.js.map +1 -0
  29. package/dist/integrations/slack.js +135 -0
  30. package/dist/integrations/slack.js.map +1 -0
  31. package/dist/integrations/store.js +101 -0
  32. package/dist/integrations/store.js.map +1 -0
  33. package/dist/mail/index.js +21 -11
  34. package/dist/mail/index.js.map +1 -1
  35. package/dist/mail/resolve.js +80 -0
  36. package/dist/mail/resolve.js.map +1 -0
  37. package/dist/projectCache.js +3 -2
  38. package/dist/projectCache.js.map +1 -1
  39. package/dist/projects.js +8 -2
  40. package/dist/projects.js.map +1 -1
  41. package/dist/routes/account.js +59 -0
  42. package/dist/routes/account.js.map +1 -0
  43. package/dist/routes/activity.js +111 -0
  44. package/dist/routes/activity.js.map +1 -0
  45. package/dist/routes/anchorReports.js +196 -0
  46. package/dist/routes/anchorReports.js.map +1 -0
  47. package/dist/routes/assignees.js +139 -0
  48. package/dist/routes/assignees.js.map +1 -0
  49. package/dist/routes/attachments.js +2 -2
  50. package/dist/routes/attachments.js.map +1 -1
  51. package/dist/routes/bodyLimit.js +60 -0
  52. package/dist/routes/bodyLimit.js.map +1 -0
  53. package/dist/routes/comments.js +27 -17
  54. package/dist/routes/comments.js.map +1 -1
  55. package/dist/routes/cors.js +10 -1
  56. package/dist/routes/cors.js.map +1 -1
  57. package/dist/routes/instance.js +164 -0
  58. package/dist/routes/instance.js.map +1 -0
  59. package/dist/routes/integrations.js +610 -0
  60. package/dist/routes/integrations.js.map +1 -0
  61. package/dist/routes/jobs.js +15 -3
  62. package/dist/routes/jobs.js.map +1 -1
  63. package/dist/routes/mcpTokens.js +119 -0
  64. package/dist/routes/mcpTokens.js.map +1 -0
  65. package/dist/routes/members.js +177 -0
  66. package/dist/routes/members.js.map +1 -0
  67. package/dist/routes/owner.js +64 -7
  68. package/dist/routes/owner.js.map +1 -1
  69. package/dist/routes/sites.js +181 -8
  70. package/dist/routes/sites.js.map +1 -1
  71. package/dist/routes/threads.js +276 -9
  72. package/dist/routes/threads.js.map +1 -1
  73. package/dist/serverless.js +39 -6
  74. package/dist/serverless.js.map +1 -1
  75. package/dist/studioReviewers.js +67 -0
  76. package/dist/studioReviewers.js.map +1 -0
  77. package/dist/vendor/adapters/outbound/sanitise.js +18 -3
  78. package/dist/vendor/types/brief.js +121 -0
  79. package/package.json +1 -1
  80. package/static/dashboard/assets/CompositeItem-CoPuxIvr.js +1 -0
  81. package/static/dashboard/assets/ConfirmDialog-DkCcJwll.js +1 -0
  82. package/static/dashboard/assets/CopyButton-BNa2pLLv.js +1 -0
  83. package/static/dashboard/assets/FieldItemContext-DQXjpFtW.js +1 -0
  84. package/static/dashboard/assets/InstallTag-SOlWl7Hx.js +1 -0
  85. package/static/dashboard/assets/SaveState-CmxB4XyX.js +6 -0
  86. package/static/dashboard/assets/_app-DNkv3HBi.js +1 -0
  87. package/static/dashboard/assets/_app-xVQe811c.js +56 -0
  88. package/static/dashboard/assets/activity-DsMa5Ja6.js +1 -0
  89. package/static/dashboard/assets/arrow-left-vQV4xhAD.js +6 -0
  90. package/static/dashboard/assets/avatar-DuPL6QD_.js +1 -0
  91. package/static/dashboard/assets/badge-BWjiIc8T.js +1 -0
  92. package/static/dashboard/assets/card-BIBfCno8.js +1 -0
  93. package/static/dashboard/assets/check-Dpx6GTdT.js +6 -0
  94. package/static/dashboard/assets/chevron-right-DKIlBUGN.js +6 -0
  95. package/static/dashboard/assets/copy-DCbhEe2L.js +6 -0
  96. package/static/dashboard/assets/createBaseUIEventDetails-C_ZVkrgp.js +1 -0
  97. package/static/dashboard/assets/createLucideIcon-C_IGE4WD.js +36 -0
  98. package/static/dashboard/assets/dialog-BT2uWf4e.js +6 -0
  99. package/static/dashboard/assets/dropdown-menu-DSXzPAwB.js +11 -0
  100. package/static/dashboard/assets/image-off-DGWejLDG.js +6 -0
  101. package/static/dashboard/assets/index-BRTBtV91.css +1 -0
  102. package/static/dashboard/assets/index-D6FWZoJT.js +129 -0
  103. package/static/dashboard/assets/label-9QsSpLMA.js +1 -0
  104. package/static/dashboard/assets/labels--UUyt9uB.js +1 -0
  105. package/static/dashboard/assets/layout-grid-UPGEmEw-.js +6 -0
  106. package/static/dashboard/assets/me-0HQsBXLU.js +1 -0
  107. package/static/dashboard/assets/parts-C29uZ5zo.js +1 -0
  108. package/static/dashboard/assets/plus-BFNS5LcY.js +6 -0
  109. package/static/dashboard/assets/s._site-D6Ep2tdc.js +1 -0
  110. package/static/dashboard/assets/s._site.comments-BRVI5gpJ.js +39 -0
  111. package/static/dashboard/assets/s._site.reviewers-CiEkZnnp.js +1 -0
  112. package/static/dashboard/assets/s._site.settings-BqLGyfEd.js +1 -0
  113. package/static/dashboard/assets/setup-dUMCPWdf.js +1 -0
  114. package/static/dashboard/assets/sign-in-CdRa-bio.js +1 -0
  115. package/static/dashboard/assets/sites-CmbtFKoo.js +1 -0
  116. package/static/dashboard/assets/studio-BHuVXWZh.js +1 -0
  117. package/static/dashboard/assets/studio-BjeTOKda.js +1 -0
  118. package/static/dashboard/assets/studio.index--kuzOs7w.js +1 -0
  119. package/static/dashboard/assets/studio.integrations-Bq6HP80a.js +1 -0
  120. package/static/dashboard/assets/studio.members-8AB1KYsw.js +1 -0
  121. package/static/dashboard/assets/sun-BCiTcgnh.js +16 -0
  122. package/static/dashboard/assets/table-BXmeI_yA.js +1 -0
  123. package/static/dashboard/assets/update-duXzIzFS.js +1 -0
  124. package/static/dashboard/assets/useBaseQuery-Cp9wivVR.js +1 -0
  125. package/static/dashboard/assets/useQuery-BZXZlOqO.js +1 -0
  126. package/static/dashboard/assets/useRender-CO8aPW06.js +1 -0
  127. package/static/dashboard/assets/users-Dvw2FCKM.js +6 -0
  128. package/static/dashboard/assets/welcome-BHKjw20b.js +11 -0
  129. package/static/dashboard/assets/you-RBpAfUMU.js +1 -0
  130. package/static/dashboard/assets/zod-BpyjQIvb.js +1 -0
  131. package/static/dashboard/index.html +17 -2
  132. package/static/widget/snag.capture.js +1 -1
  133. package/static/widget/snag.dock.js +1 -1
  134. package/static/widget/snag.panels.js +1 -1
  135. package/static/widget/snag.runtime.js +2 -2
  136. package/static/widget/snag.text.js +1 -1
  137. package/vercel.json +4 -0
  138. package/static/dashboard/assets/index-DsUJ96yc.css +0 -1
  139. package/static/dashboard/assets/index-DultqpS7.js +0 -1
@@ -0,0 +1,196 @@
1
+ import { Hono } from "hono";
2
+ import { randomUUID } from "node:crypto";
3
+ import { ID_PREFIX } from "../vendor/types/names.js";
4
+ function fail(c, status, code, message, details) {
5
+ return c.json({ error: { code, message, ...(details ? { details } : {}), requestId: c.get("requestId") } }, status);
6
+ }
7
+ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
8
+ function rowId(wire, prefix) {
9
+ if (typeof wire !== "string")
10
+ return null;
11
+ const bare = wire.startsWith(prefix) ? wire.slice(prefix.length) : wire;
12
+ return UUID.test(bare) ? bare.toLowerCase() : null;
13
+ }
14
+ /** 03 §5's enum, not free text. `manual` is reported by v2 repair, never by `resolve()`. */
15
+ const STRATEGY = new Set([
16
+ "testid",
17
+ "domid",
18
+ "css",
19
+ "aria",
20
+ "text-exact",
21
+ "text-fuzzy",
22
+ "path-rect",
23
+ "none",
24
+ "manual",
25
+ ]);
26
+ /**
27
+ * foundations §14.2's ordering. `pending` is deliberately absent — it is not a
28
+ * settled state, and §6.7 rejects it: a client reporting "I have not finished
29
+ * yet" is not reporting an outcome.
30
+ */
31
+ const RANK = { orphaned: 0, approximate: 1, anchored: 2 };
32
+ const MAX_REPORTS = 50;
33
+ /** §6.7: idempotent within 60 s per (thread, build, strategy). */
34
+ const DEDUPE_MS = 60_000;
35
+ const RATE_WINDOW_MS = 60_000;
36
+ export function anchorReportRoutes(sql, projects, perMinute) {
37
+ const app = new Hono();
38
+ app.post("/api/v1/projects/:uid/anchor-reports", async (c) => {
39
+ const p = await projects.get(c.req.param("uid")).catch(() => null);
40
+ if (!p)
41
+ return fail(c, 404, "project_not_found", "No project with that uid.");
42
+ const session = c.get("session");
43
+ if (!session) {
44
+ return fail(c, 401, "unauthorized", "Open your review link, or reload the page, and try again.");
45
+ }
46
+ const body = (await c.req.json().catch(() => null));
47
+ const reports = Array.isArray(body?.reports) ? body.reports : null;
48
+ if (!reports || reports.length === 0 || reports.length > MAX_REPORTS) {
49
+ return fail(c, 400, "validation_failed", `reports must be an array of 1 to ${MAX_REPORTS} items.`, { field: "reports" });
50
+ }
51
+ // Validate EVERY report before writing ANY of them. A batch that is half
52
+ // valid should not leave half a batch in the telemetry — the client has no
53
+ // way to learn which half landed, since the success case is a bare 204.
54
+ const parsed = [];
55
+ for (const r of reports) {
56
+ const threadRow = rowId(r["threadId"], ID_PREFIX.thread);
57
+ if (!threadRow) {
58
+ return fail(c, 400, "validation_failed", "threadId must be a thread id.", { field: "threadId" });
59
+ }
60
+ const state = String(r["state"]);
61
+ if (!(state in RANK)) {
62
+ return fail(c, 400, "validation_failed", "state must be one of orphaned, approximate, anchored — 'pending' is not an outcome.", { field: "state" });
63
+ }
64
+ const strategy = String(r["strategy"]);
65
+ if (!STRATEGY.has(strategy)) {
66
+ // 422, not 400, and §6.7 says why: a telemetry table that accepts
67
+ // anything measures nothing.
68
+ return fail(c, 422, "validation_failed", `Unknown anchor strategy '${strategy}'.`, {
69
+ field: "strategy",
70
+ });
71
+ }
72
+ const confidence = Number(r["confidence"]);
73
+ if (!Number.isFinite(confidence) || confidence < 0 || confidence > 1) {
74
+ return fail(c, 400, "validation_failed", "confidence must be between 0 and 1.", {
75
+ field: "confidence",
76
+ });
77
+ }
78
+ const ms = Number(r["ms"]);
79
+ parsed.push({
80
+ threadRow,
81
+ state,
82
+ confidence,
83
+ strategy,
84
+ build: typeof r["build"] === "string" && r["build"] ? r["build"] : null,
85
+ ms: Number.isFinite(ms) ? Math.round(ms) : null,
86
+ });
87
+ }
88
+ /**
89
+ * Rate limit AFTER validation, so a malformed batch still gets its 4xx
90
+ * rather than being silently swallowed by a limit it also tripped — the
91
+ * developer integrating this needs the error more than we need the saving.
92
+ */
93
+ const now = new Date();
94
+ const windowStart = new Date(now.getTime() - RATE_WINDOW_MS);
95
+ const [counter] = await sql `
96
+ INSERT INTO rate_counters (org_id, bucket_key, window_start, count, expires_at)
97
+ VALUES (${p.org_id}, ${`anch:${session.sid}`}, ${now}, ${parsed.length},
98
+ ${new Date(now.getTime() + RATE_WINDOW_MS)})
99
+ ON CONFLICT (org_id, bucket_key) DO UPDATE
100
+ SET count = CASE WHEN rate_counters.window_start < ${windowStart} THEN ${parsed.length}
101
+ ELSE rate_counters.count + ${parsed.length} END,
102
+ window_start = CASE WHEN rate_counters.window_start < ${windowStart} THEN ${now}
103
+ ELSE rate_counters.window_start END,
104
+ expires_at = ${new Date(now.getTime() + RATE_WINDOW_MS)}
105
+ RETURNING count::text
106
+ `;
107
+ // Dropped, not queued, and not an error. §12.1 rule 8.
108
+ if (Number(counter?.count ?? 0) > perMinute())
109
+ return c.body(null, 204);
110
+ await sql.begin(async (tx) => {
111
+ await tx `SELECT set_config('app.org_id', ${p.org_id}, true)`;
112
+ for (const r of parsed) {
113
+ const [thread] = await tx `
114
+ SELECT id, anchor_state, anchor_state_build, last_anchor_check, version
115
+ FROM threads WHERE id = ${r.threadRow} AND project_id = ${p.id} AND deleted_at IS NULL
116
+ `;
117
+ // Not this project's thread. Skipped rather than failing the batch:
118
+ // the 404 case §6.7 names is a caller sending someone else's id, and
119
+ // by here we have already taken the rate-limit hit for it. A deleted
120
+ // thread is the same shape and is even less worth an error.
121
+ if (!thread)
122
+ continue;
123
+ /**
124
+ * §6.7's 60-second idempotency, by natural key rather than a header. A
125
+ * re-rendering SPA that resolves the same pin four times in a second
126
+ * is not four observations; it is one, seen four times.
127
+ */
128
+ const [recent] = await tx `
129
+ SELECT count(*)::int AS n FROM anchor_events
130
+ WHERE thread_id = ${thread.id}
131
+ AND strategy = ${r.strategy}
132
+ AND build IS NOT DISTINCT FROM ${r.build}
133
+ AND at > ${new Date(now.getTime() - DEDUPE_MS)}
134
+ `;
135
+ if ((recent?.n ?? 0) > 0)
136
+ continue;
137
+ /**
138
+ * THE MONOTONIC MERGE (§6.7, foundations §14.2 normative).
139
+ *
140
+ * A new build is exactly when a pin is allowed to get worse — that is
141
+ * what keeps this monotonic rather than a one-way ratchet that could
142
+ * never report a real regression. Otherwise the maximum wins within
143
+ * the scope, and when neither side knows a build the scope is a
144
+ * rolling 24 hours.
145
+ */
146
+ const newBuild = !!r.build && r.build !== thread.anchor_state_build;
147
+ const stale = !r.build &&
148
+ !thread.anchor_state_build &&
149
+ !!thread.last_anchor_check &&
150
+ now.getTime() - new Date(thread.last_anchor_check).getTime() > 24 * 60 * 60 * 1000;
151
+ const resets = newBuild || stale;
152
+ const next = resets
153
+ ? r.state
154
+ : (RANK[r.state] ?? 0) > (RANK[thread.anchor_state] ?? 0)
155
+ ? r.state
156
+ : thread.anchor_state;
157
+ const applied = next !== thread.anchor_state || resets;
158
+ await tx `
159
+ INSERT INTO anchor_events (id, org_id, project_id, thread_id, state, confidence,
160
+ strategy, actor_kind, actor_id, build, ms, applied)
161
+ VALUES (${randomUUID()}, ${p.org_id}, ${p.id}, ${thread.id}, ${r.state}::snag_anchor_state,
162
+ ${r.confidence}, ${r.strategy}, 'runtime', NULL, ${r.build}, ${r.ms}, ${applied})
163
+ `;
164
+ /**
165
+ * `updated_at` and `version` move ONLY when the state actually
166
+ * changed. Telemetry must not wake a polling client, and it must not
167
+ * enqueue an outbox row for a non-event — a reviewer being emailed
168
+ * because somebody's browser re-measured a pin is the kind of noise
169
+ * that teaches people to filter the sender.
170
+ */
171
+ if (next !== thread.anchor_state) {
172
+ await tx `
173
+ UPDATE threads
174
+ SET anchor_state = ${next}::snag_anchor_state,
175
+ anchor_state_build = ${r.build ?? thread.anchor_state_build},
176
+ last_anchor_check = ${now},
177
+ updated_at = ${now},
178
+ version = version + 1
179
+ WHERE id = ${thread.id}
180
+ `;
181
+ }
182
+ else {
183
+ await tx `
184
+ UPDATE threads
185
+ SET last_anchor_check = ${now},
186
+ anchor_state_build = ${r.build ?? thread.anchor_state_build}
187
+ WHERE id = ${thread.id}
188
+ `;
189
+ }
190
+ }
191
+ });
192
+ return c.body(null, 204);
193
+ });
194
+ return app;
195
+ }
196
+ //# sourceMappingURL=anchorReports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anchorReports.js","sourceRoot":"","sources":["../../src/routes/anchorReports.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,139 @@
1
+ import { Hono } from "hono";
2
+ import { randomUUID } from "node:crypto";
3
+ import { ID_PREFIX } from "../vendor/types/names.js";
4
+ /**
5
+ * WHO IS IN THE POOL — §6.4b's predicate, in one place, over an alias `r`.
6
+ * Blocked and erased reviewers leave the pool but keep their existing
7
+ * assignments (un-assigning on block would rewrite history on threads
8
+ * somebody is mid-conversation on); a guest who exchanged a session but never
9
+ * wrote is not in it (the matrix's "be assigned: ✓ once they have written").
10
+ * The thread PATCH validates a candidate against the same predicate, which is
11
+ * why it is exported rather than inlined in the query below.
12
+ */
13
+ export function inPool(t) {
14
+ return t `r.blocked_at IS NULL AND r.erased_at IS NULL
15
+ AND (r.user_id IS NOT NULL OR r.invited_by IS NOT NULL
16
+ OR r.thread_count > 0 OR r.comment_count > 0)`;
17
+ }
18
+ function fail(c, status, code, message, details) {
19
+ return c.json({ error: { code, message, ...(details ? { details } : {}), requestId: c.get("requestId") } }, status);
20
+ }
21
+ /** Foundations §5's `Reviewer`, plus the two derived flags the dropdown groups by. */
22
+ export function shapeReviewer(r, withEmail) {
23
+ return {
24
+ id: ID_PREFIX.reviewer + String(r["id"]),
25
+ name: String(r["name"] ?? ""),
26
+ kind: String(r["kind"] ?? "guest"),
27
+ ...(withEmail && r["email"] ? { email: String(r["email"]) } : {}),
28
+ ...(r["avatar_url"] ? { avatarUrl: String(r["avatar_url"]) } : {}),
29
+ // Derived on the wire, not stored twice — so the dropdown can put "the
30
+ // studio" above "people who have commented". NOT a permission.
31
+ isTeam: !!r["is_team"],
32
+ isMe: !!r["is_me"],
33
+ };
34
+ }
35
+ export function assigneeRoutes(deps) {
36
+ const { sql, projects } = deps;
37
+ const app = new Hono();
38
+ const inOrg = (orgId, fn) => sql.begin(async (tx) => {
39
+ await tx `SELECT set_config('app.org_id', ${orgId}, true)`;
40
+ return fn(tx);
41
+ });
42
+ app.get("/api/v1/projects/:uid/assignees", async (c) => {
43
+ const p = await projects.get(c.req.param("uid"));
44
+ if (!p)
45
+ return fail(c, 404, "project_not_found", "No project with that uid.");
46
+ const owner = c.get("owner");
47
+ const session = c.get("session");
48
+ const asOwner = !!owner && owner.orgId === p.org_id;
49
+ if (!asOwner && !session) {
50
+ return fail(c, 401, "unauthorized", "Open your review link, or reload the page, and try again.");
51
+ }
52
+ // Emails are for the people who can route work, not for a client reading
53
+ // names: a link session sees who is in the pool, never the studio's
54
+ // addresses.
55
+ const mayAssign = asOwner || !!session?.perm.includes("thread:assign");
56
+ // A prefix match on name and email — the pool is single- to double-digit
57
+ // for this product's audience; a convenience, not a search feature.
58
+ const q = (c.req.query("q") ?? "").trim().slice(0, 80);
59
+ const limit = Math.min(Math.max(Number(c.req.query("limit")) || 100, 1), 200);
60
+ const rows = await inOrg(p.org_id, (tx) => tx `
61
+ SELECT r.id, r.name, r.email, r.kind, r.avatar_url,
62
+ (r.user_id IS NOT NULL) AS is_team,
63
+ ${asOwner ? tx `(r.user_id = ${owner.userId}::uuid)` : tx `(r.id = ${session.sub}::uuid)`} AS is_me,
64
+ count(*) OVER () AS total
65
+ FROM reviewers r
66
+ WHERE r.project_id = ${p.id}::uuid
67
+ AND ${inPool(tx)}
68
+ ${q ? tx `AND (r.name ILIKE ${q + "%"} OR r.email ILIKE ${q + "%"})` : tx ``}
69
+ -- The studio first (you assign to a colleague more often than to
70
+ -- anyone else), then most recently active, which puts the person who
71
+ -- just commented at the top of the list you opened because they did.
72
+ ORDER BY is_team DESC, r.last_seen_at DESC
73
+ LIMIT ${limit}
74
+ `);
75
+ c.header("Cache-Control", "private, max-age=30");
76
+ return c.json({
77
+ data: rows.map((r) => shapeReviewer(r, mayAssign)),
78
+ total: Number(rows[0]?.["total"] ?? 0),
79
+ });
80
+ });
81
+ /**
82
+ * Naming a person who has not written yet — DESIGN.md Q4's *+ Add person*,
83
+ * and the case D3 needs on day one: a question assigned to a client BEFORE
84
+ * that client has said anything.
85
+ *
86
+ * A PLACEHOLDER: `kind='guest'`, no secret, `invited_by` set. A name to
87
+ * assign to and not a credential — no exchange can ever authenticate as it.
88
+ *
89
+ * Dashboard only in v1. §6.4b also admits a session holding `thread:assign`,
90
+ * but `invited_by` is a `users.id` and a team-link session carries no user;
91
+ * refusing with a sentence beats inventing an inviter.
92
+ */
93
+ app.post("/api/v1/projects/:uid/assignees", async (c) => {
94
+ const p = await projects.get(c.req.param("uid"));
95
+ if (!p)
96
+ return fail(c, 404, "project_not_found", "No project with that uid.");
97
+ const owner = c.get("owner");
98
+ const asOwner = !!owner && owner.orgId === p.org_id;
99
+ if (!asOwner) {
100
+ return fail(c, 403, "forbidden", "Adding a person to assign to is done from the dashboard.");
101
+ }
102
+ const body = (await c.req.json().catch(() => null));
103
+ const name = typeof body?.name === "string" ? body.name.trim().slice(0, 80) : "";
104
+ if (!name)
105
+ return fail(c, 400, "validation_failed", "Give the person a name.", { field: "name" });
106
+ const emailRaw = typeof body?.email === "string" ? body.email.trim().toLowerCase() : "";
107
+ if (emailRaw && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailRaw)) {
108
+ return fail(c, 400, "validation_failed", "That does not look like an email address.", { field: "email" });
109
+ }
110
+ const email = emailRaw || null;
111
+ const [row, created] = await inOrg(p.org_id, async (tx) => {
112
+ if (email) {
113
+ // The same person named twice is one person: an unerased row with
114
+ // that address — a placeholder, a link reviewer, a studio member —
115
+ // is returned rather than duplicated.
116
+ const [same] = await tx `
117
+ SELECT r.id, r.name, r.email, r.kind, r.avatar_url, (r.user_id IS NOT NULL) AS is_team,
118
+ (r.user_id = ${owner.userId}::uuid) AS is_me
119
+ FROM reviewers r
120
+ WHERE r.project_id = ${p.id}::uuid AND lower(r.email) = ${email} AND r.erased_at IS NULL
121
+ ORDER BY r.last_seen_at DESC
122
+ LIMIT 1
123
+ `;
124
+ if (same)
125
+ return [same, false];
126
+ }
127
+ const id = randomUUID();
128
+ const [made] = await tx `
129
+ INSERT INTO reviewers (id, org_id, project_id, kind, name, email, invited_by)
130
+ VALUES (${id}::uuid, ${p.org_id}::uuid, ${p.id}::uuid, 'guest', ${name}, ${email}, ${owner.userId}::uuid)
131
+ RETURNING id, name, email, kind, avatar_url, false AS is_team, false AS is_me
132
+ `;
133
+ return [made, true];
134
+ });
135
+ return c.json(shapeReviewer(row, true), created ? 201 : 200);
136
+ });
137
+ return app;
138
+ }
139
+ //# sourceMappingURL=assignees.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assignees.js","sourceRoot":"","sources":["../../src/routes/assignees.ts"],"names":[],"mappings":"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"}
@@ -152,8 +152,8 @@ export function attachmentRoutes(deps) {
152
152
  return app;
153
153
  }
154
154
  /** A9b: derived server-side from bucket presence, never probed by the widget. */
155
- export async function features(sql, keys) {
156
- const st = await storageStatus(sql, keys);
155
+ export async function features(sql, keys, env = process.env) {
156
+ const st = await storageStatus(sql, keys, env);
157
157
  return { screenshots: st.connected, uploads: st.connected };
158
158
  }
159
159
  //# sourceMappingURL=attachments.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"attachments.js","sourceRoot":"","sources":["../../src/routes/attachments.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"attachments.js","sourceRoot":"","sources":["../../src/routes/attachments.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * 05 §9.3 — the JSON body cap, which was registered and enforced by nothing.
3
+ *
4
+ * `SNAGSET_MAX_BODY_BYTES` has been in the config registry since 08 §4 with a
5
+ * 1 MB default, cited by name in two specs, printed by `snagset env` — and read
6
+ * by no code at all. So every JSON route on this server would read whatever it
7
+ * was sent, and the only thing standing between an instance and a body large
8
+ * enough to exhaust its memory was the hosting platform's own proxy, which a
9
+ * self-hoster on their own box does not have.
10
+ *
11
+ * ── THE TWO NUMBERS, AND WHY ONLY ONE IS TUNABLE ──
12
+ *
13
+ * 05 §9.3 caps JSON at **256 KB** and says plainly it is *"not operator-
14
+ * tunable"*. 08 §4 caps binary routes at `SNAGSET_MAX_BODY_BYTES` (1 MB) and
15
+ * that one IS tunable. They are different limits for different reasons: the
16
+ * JSON cap protects the parser, and every JSON body this API accepts is small
17
+ * by construction — a comment, an anchor, a capture context whose breadcrumbs
18
+ * are already truncated server-side. An operator raising it is not configuring
19
+ * the product, they are disabling a bound the wire format does not need.
20
+ *
21
+ * Binary is different: images are ≤ 256 KB by construction, but the ceiling is
22
+ * the operator's because their proxy and their bucket are.
23
+ *
24
+ * ── WHY `Content-Length` AND NOT A COUNTING STREAM ──
25
+ *
26
+ * Rejecting on the declared length is the whole point: it costs nothing and it
27
+ * happens BEFORE the body is read. A stream that counts as it goes has already
28
+ * accepted the bytes it is measuring. A liar who declares 1 KB and sends 10 MB
29
+ * defeats the header check — and is then bounded by the platform's own limit
30
+ * and by the fact that `c.req.json()` throws on a truncated body, which is the
31
+ * same place an unbounded read would have failed anyway. The header check is
32
+ * the cheap 99%, not the security boundary; it exists so an honest client with
33
+ * a runaway payload gets a clean `413` instead of an OOM.
34
+ */
35
+ /** 05 §9.3, and deliberately not `SNAGSET_MAX_BODY_BYTES`. */
36
+ export const JSON_BODY_CAP = 256 * 1024;
37
+ export function bodyLimit(binaryBytes) {
38
+ return async (c, next) => {
39
+ const method = c.req.method;
40
+ if (method === "GET" || method === "HEAD" || method === "OPTIONS")
41
+ return next();
42
+ const declared = Number(c.req.header("content-length") ?? "");
43
+ if (!Number.isFinite(declared) || declared <= 0)
44
+ return next();
45
+ const type = (c.req.header("content-type") ?? "").toLowerCase();
46
+ const isJson = type.includes("json") || type === "";
47
+ const cap = isJson ? JSON_BODY_CAP : binaryBytes();
48
+ if (declared > cap) {
49
+ return c.json({
50
+ error: {
51
+ code: "body_too_large",
52
+ message: `That request body is ${Math.round(declared / 1024)} KB; the limit here is ${Math.round(cap / 1024)} KB.`,
53
+ requestId: c.get("requestId"),
54
+ },
55
+ }, 413);
56
+ }
57
+ return next();
58
+ };
59
+ }
60
+ //# sourceMappingURL=bodyLimit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bodyLimit.js","sourceRoot":"","sources":["../../src/routes/bodyLimit.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,8DAA8D;AAC9D,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,GAAG,IAAI,CAAC;AAExC,MAAM,UAAU,SAAS,CAAC,WAAyB;IACjD,OAAO,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;QACvB,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;QAC5B,IAAI,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,IAAI,EAAE,CAAC;QAEjF,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9D,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,IAAI,CAAC;YAAE,OAAO,IAAI,EAAE,CAAC;QAE/D,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QAChE,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,KAAK,EAAE,CAAC;QACpD,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;QAEnD,IAAI,QAAQ,GAAG,GAAG,EAAE,CAAC;YACnB,OAAO,CAAC,CAAC,IAAI,CACX;gBACE,KAAK,EAAE;oBACL,IAAI,EAAE,gBAAgB;oBACtB,OAAO,EAAE,wBAAwB,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,0BAA0B,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM;oBAClH,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"}
@@ -3,6 +3,7 @@ import { randomUUID } from "node:crypto";
3
3
  import { ID_PREFIX } from "../vendor/types/names.js";
4
4
  import { csrfOk } from "./owner.js";
5
5
  import { mcpAllows, scopeDenied, checkWriteBudget, budgetExhausted, recordAgentWrite, agentReviewer, } from "./mcpAuth.js";
6
+ import { studioReviewerId } from "../studioReviewers.js";
6
7
  import { queueCommentNotice } from "../mail/notify.js";
7
8
  function fail(c, status, code, message, details) {
8
9
  return c.json({ error: { code, message, ...(details ? { details } : {}), requestId: c.get("requestId") } }, status);
@@ -22,7 +23,7 @@ export function commentRoutes(deps) {
22
23
  if (!threadRow)
23
24
  return fail(c, 404, "thread_not_found", "No such thread.");
24
25
  const [thread] = await sql `
25
- SELECT t.id, t.project_id, t.org_id, t.private, p.uid AS project_uid,
26
+ SELECT t.id, t.project_id, t.org_id, t.private, p.uid AS project_uid, p.status AS project_status,
26
27
  t.key,
27
28
  -- The page URL lives INSIDE the capture context, not in a column
28
29
  -- of its own (05 §3.5). Two arrows, not one, so it arrives as
@@ -93,6 +94,13 @@ export function commentRoutes(deps) {
93
94
  if (asAgent && !asOwner && thread.private) {
94
95
  return fail(c, 403, "forbidden", "This thread is team-only. An agent cannot reply on it.");
95
96
  }
97
+ // D91 — the widget switch. A paused site refuses the WIDGET's writes (05
98
+ // §4.9 layer 6, `project_paused`); the studio's own replies from the
99
+ // dashboard go on, because the switch is about the client's page, not
100
+ // about the team's triage of what already arrived.
101
+ if (asSession && !asOwner && thread.project_status !== "active") {
102
+ return fail(c, 403, "project_paused", "This site's widget is switched off. Its owner can switch it back on.");
103
+ }
96
104
  // 07 §8.4's write budget, checked before the write. §8.6 mitigation 5.
97
105
  if (asAgent && !asOwner && !asSession) {
98
106
  const spent = await checkWriteBudget(sql, mcp.tokenId);
@@ -206,22 +214,17 @@ export function commentRoutes(deps) {
206
214
  });
207
215
  }
208
216
  else {
217
+ // The owner's own reviewer row in this project — materialised on
218
+ // project and membership create since D90, found-or-created here for
219
+ // anything older (studioReviewers.ts).
209
220
  const o = owner;
210
- const [existing] = await tx `
211
- SELECT id FROM reviewers
212
- WHERE project_id = ${thread.project_id}::uuid AND user_id = ${o.userId}::uuid AND kind = 'verified'
213
- `;
214
- if (existing) {
215
- reviewerId = existing.id;
216
- }
217
- else {
218
- reviewerId = randomUUID();
219
- await tx `
220
- INSERT INTO reviewers (id, org_id, project_id, kind, name, email, user_id)
221
- VALUES (${reviewerId}::uuid, ${thread.org_id}::uuid, ${thread.project_id}::uuid, 'verified',
222
- ${o.name || o.email}, ${o.email}, ${o.userId}::uuid)
223
- `;
224
- }
221
+ reviewerId = await studioReviewerId(tx, {
222
+ orgId: thread.org_id,
223
+ projectId: thread.project_id,
224
+ userId: o.userId,
225
+ name: o.name,
226
+ email: o.email,
227
+ });
225
228
  }
226
229
  // Locked here, not read-then-trusted: `seq` and both counters are
227
230
  // derived from THIS row under the lock, so two replies landing at once
@@ -244,6 +247,13 @@ export function commentRoutes(deps) {
244
247
  version = version + 1,
245
248
  updated_at = now()
246
249
  WHERE id = ${thread.id}::uuid
250
+ `;
251
+ // The author's own counter (05 §3.4) — what puts a person who has only
252
+ // ever replied into the assignee pool (§6.4b), and floats whoever just
253
+ // wrote to the top of it.
254
+ await tx `
255
+ UPDATE reviewers SET comment_count = comment_count + 1, last_seen_at = now()
256
+ WHERE id = ${reviewerId}::uuid
247
257
  `;
248
258
  const [author] = await tx `
249
259
  SELECT id, name, kind FROM reviewers WHERE id = ${reviewerId}::uuid
@@ -276,7 +286,7 @@ export function commentRoutes(deps) {
276
286
  * whatever forwards, backs up or indexes it — for a comment the product
277
287
  * promises is private. Not worth the surprise for a notification.
278
288
  */
279
- if (!wantPrivate && deps.notifications) {
289
+ if (!wantPrivate && (await deps.notifications())) {
280
290
  await queueCommentNotice(tx, {
281
291
  orgId: thread.org_id,
282
292
  projectId: thread.project_id,
@@ -1 +1 @@
1
- {"version":3,"file":"comments.js","sourceRoot":"","sources":["../../src/routes/comments.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"comments.js","sourceRoot":"","sources":["../../src/routes/comments.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { HTTP_HEADER } from "../vendor/types/names.js";
2
+ import { isLocalOrigin, originMatchesDomain } from "../domain.js";
2
3
  /**
3
4
  * The request headers a widget may send — 05 §2.3's request rows, plus the two
4
5
  * standard ones. Built from the registry rather than typed out, so adding a
@@ -136,7 +137,15 @@ export function corsForProjects(sql, lookup) {
136
137
  const project = await lookup(uid).catch(() => null);
137
138
  if (project) {
138
139
  const patterns = await patternsFor(project.id);
139
- const ok = isAllowed(patterns, origin);
140
+ /**
141
+ * Three ways in (D92, 05 §4.3 as amended): an exact or wildcard
142
+ * origin from the allow-list; the site's DOMAIN — its host or any
143
+ * subdomain, any scheme, any port; and the developer's own machine
144
+ * (rule 4), which the spec allows by default and which had never been
145
+ * implemented. The domain rides the project cache, so a change lands
146
+ * within the same ten seconds as everything else about a project.
147
+ */
148
+ const ok = isAllowed(patterns, origin) || originMatchesDomain(project.domain ?? "", origin) || isLocalOrigin(origin);
140
149
  /**
141
150
  * The verdict, stashed for the config route (05 §7.2's origin-aware
142
151
  * body, D69). Computed HERE and not re-derived in the route because