@satanwagen/reviewkit 0.1.1 → 0.1.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.
@@ -296,11 +296,15 @@ export function cmdServe(cwd) {
296
296
  findings.set(item.id, toFinding(item, seq));
297
297
  queuePush(item);
298
298
  };
299
+ // Tombstone unconditionally: a delete for an id this process never saw (a
300
+ // ghost row left in the Emblema tile by an older/restarted agent) must still
301
+ // be reportable under `deleted`, or the row can never be cleared.
299
302
  const dropItem = (id) => {
300
- if (findings.delete(id)) {
301
- seq += 1;
302
- deletedIds.set(id, seq);
303
- }
303
+ // Already tombstoned and not live: nothing changed — don't churn the
304
+ // cursor (rooms replay their `deleted` list on every reconnect).
305
+ if (!findings.delete(id) && deletedIds.has(id)) return;
306
+ seq += 1;
307
+ deletedIds.set(id, seq);
304
308
  };
305
309
 
306
310
  /* -- realtime push to the Emblema intake (headers per contract v2) -- */
@@ -438,7 +442,7 @@ export function cmdServe(cwd) {
438
442
  /* -- HTTP API -- */
439
443
  const CORS = {
440
444
  'access-control-allow-origin': '*',
441
- 'access-control-allow-methods': 'GET, POST, OPTIONS',
445
+ 'access-control-allow-methods': 'GET, POST, DELETE, OPTIONS',
442
446
  'access-control-allow-headers': 'content-type, authorization, x-reviewkit-key-id',
443
447
  };
444
448
  const send = (res, status, body) => {
@@ -555,7 +559,15 @@ export function cmdServe(cwd) {
555
559
  return send(res, 400, { ok: false, error: 'invalid JSON' });
556
560
  }
557
561
  const mapped = STATUS_MAP[status];
558
- if (!mapped) return send(res, 400, { ok: false, error: 'status must be open|accepted|dismissed|fixed' });
562
+ if (!mapped) {
563
+ // Echo what arrived: the live 400s on `open` were an OLD installed
564
+ // agent, and a bare "must be …" message made that undiagnosable.
565
+ return send(res, 400, {
566
+ ok: false,
567
+ error: `status must be open|accepted|dismissed|fixed (received ${JSON.stringify(status ?? null)})`,
568
+ received: status ?? null,
569
+ });
570
+ }
559
571
  const finding = findings.get(decodeURIComponent(statusMatch[1]));
560
572
  if (!finding) return send(res, 404, { ok: false, error: 'unknown finding' });
561
573
  const ws = sockets.get(finding._route);
@@ -567,6 +579,24 @@ export function cmdServe(cwd) {
567
579
  });
568
580
  return;
569
581
  }
582
+ // DELETE /findings/{id} (POST …/delete for clients that cannot send DELETE).
583
+ // IDEMPOTENT: an unknown id still answers 200 and is tombstoned, so a ghost
584
+ // row left in the tile by an older/restarted agent can always be cleared.
585
+ // No body is read — the id is entirely in the path.
586
+ const deleteMatch =
587
+ (req.method === 'DELETE' && url.pathname.match(/^\/api\/emblema\/findings\/([^/]+)$/)) ||
588
+ (req.method === 'POST' && url.pathname.match(/^\/api\/emblema\/findings\/([^/]+)\/delete$/));
589
+ if (deleteMatch) {
590
+ const id = decodeURIComponent(deleteMatch[1]);
591
+ const finding = findings.get(id);
592
+ // Write-back first, while _route is still known: the site pin must
593
+ // disappear for every reviewer, not just in the tile.
594
+ const ws = finding && sockets.get(finding._route);
595
+ if (ws && ws.readyState === 1) ws.send(JSON.stringify({ t: 'item:delete', id }));
596
+ dropItem(id);
597
+ send(res, 200, { ok: true, id, known: !!finding });
598
+ return;
599
+ }
570
600
  send(res, 404, { ok: false, error: 'not found' });
571
601
  });
572
602
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@satanwagen/reviewkit",
3
- "version": "0.1.1",
4
- "description": "Drop-in visual review & feedback layer for React sites. Reviewers annotate the live page; nothing is ever applied \u2014 changes are recorded as a portable session for a coding agent.",
3
+ "version": "0.1.2",
4
+ "description": "Drop-in visual review & feedback layer for React sites. Reviewers annotate the live page; nothing is ever applied changes are recorded as a portable session for a coding agent.",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "sideEffects": false,
@@ -69,4 +69,4 @@
69
69
  "bin": {
70
70
  "reviewkit-emblema": "./cli/emblema-sync.mjs"
71
71
  }
72
- }
72
+ }