@loupekit/sdk 0.2.0 → 0.2.1-next.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +107 -52
- package/package.json +21 -6
package/README.md
CHANGED
|
@@ -1,39 +1,67 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
fully-contextualized, actionable backlog.
|
|
3
|
+
<a href="https://mohamed-ashraf-elsaed.github.io/loupe/">
|
|
4
|
+
<img src="https://raw.githubusercontent.com/mohamed-ashraf-elsaed/loupe/main/docs/store/promo-marquee-1400x560.jpg" alt="Loupe — Pin feedback to the live UI. Hand it to Claude." width="100%" />
|
|
5
|
+
</a>
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
<h1>@loupekit/sdk</h1>
|
|
8
|
+
|
|
9
|
+
<p><strong>The embeddable visual-feedback widget for the web.</strong><br />
|
|
10
|
+
Inspect any element on your live product, pin a comment to it, capture a screenshot —<br />
|
|
11
|
+
comments re-anchor across redeploys and flow to Claude Code as an actionable backlog.</p>
|
|
12
|
+
|
|
13
|
+
<p>
|
|
14
|
+
<a href="https://www.npmjs.com/package/@loupekit/sdk"><img src="https://img.shields.io/npm/v/@loupekit/sdk?color=4a55d6&label=npm" alt="npm version" /></a>
|
|
15
|
+
<a href="https://www.npmjs.com/package/@loupekit/sdk"><img src="https://img.shields.io/npm/dm/@loupekit/sdk?color=4a55d6" alt="npm downloads" /></a>
|
|
16
|
+
<img src="https://img.shields.io/npm/types/@loupekit/sdk?color=4a55d6" alt="TypeScript types" />
|
|
17
|
+
<img src="https://img.shields.io/npm/l/@loupekit/sdk?color=4a55d6" alt="MIT license" />
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
<p>
|
|
21
|
+
<a href="https://mohamed-ashraf-elsaed.github.io/loupe/"><b>Website</b></a> ·
|
|
22
|
+
<a href="https://github.com/mohamed-ashraf-elsaed/loupe"><b>GitHub</b></a> ·
|
|
23
|
+
<a href="https://github.com/mohamed-ashraf-elsaed/loupe/blob/main/CHANGELOG.md"><b>Changelog</b></a> ·
|
|
24
|
+
<a href="https://www.npmjs.com/package/@loupekit/mcp"><b>MCP server</b></a>
|
|
25
|
+
</p>
|
|
26
|
+
|
|
27
|
+
</div>
|
|
11
28
|
|
|
12
29
|
---
|
|
13
30
|
|
|
14
|
-
##
|
|
31
|
+
## Overview
|
|
32
|
+
|
|
33
|
+
Traditional feedback — _"the revenue card looks off on the dashboard"_ — loses the one thing
|
|
34
|
+
an engineer needs: **which element, in what state, on which page.** Loupe captures all of it at
|
|
35
|
+
the moment of the comment, so the feedback stays actionable even after the UI changes underneath it.
|
|
15
36
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
37
|
+
<div align="center">
|
|
38
|
+
<img src="https://raw.githubusercontent.com/mohamed-ashraf-elsaed/loupe/main/docs/store/screenshot-1-inspect.jpg" alt="Pin a comment to any element" width="90%" />
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
## Table of contents
|
|
42
|
+
|
|
43
|
+
- [Features](#features)
|
|
44
|
+
- [Install](#install)
|
|
45
|
+
- [Quick start](#quick-start)
|
|
46
|
+
- [Re-anchoring across redeploys](#re-anchoring-across-redeploys)
|
|
47
|
+
- [Configuration](#configuration)
|
|
48
|
+
- [Redaction](#redaction)
|
|
49
|
+
- [Auth model](#auth-model)
|
|
50
|
+
- [Storage seam](#storage-seam)
|
|
51
|
+
- [The loop](#the-loop)
|
|
52
|
+
- [Related packages](#related-packages)
|
|
21
53
|
|
|
22
54
|
## Features
|
|
23
55
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
- 🧩 **Shadow-DOM isolation** — the widget's CSS never leaks into your page and vice-versa.
|
|
34
|
-
- 🔌 **Pluggable storage** — talks to the Loupe backend, or persists to `localStorage` for
|
|
35
|
-
offline/demo use.
|
|
36
|
-
- 🤖 **Claude-ready** — every comment carries the context Claude Code needs to make the fix.
|
|
56
|
+
| | |
|
|
57
|
+
| --- | --- |
|
|
58
|
+
| 🎯 **Click-to-comment inspector** | Hover-highlight any element, click to pin a comment. |
|
|
59
|
+
| ▭ **Free-region screenshots** | Drag a free-size box, screenshot exactly that area, comment on it. The region anchors to the element under its center, so it tracks responsive reflow and scrolling. |
|
|
60
|
+
| 🔁 **Redeploy-surviving re-anchoring** | A multi-signal fingerprint (stable id/testid, CSS path, XPath, text, attributes, position) re-locates the element on the current page; if it can't, the pin **detaches** instead of pointing at the wrong thing. |
|
|
61
|
+
| 📸 **Screenshot capture** | `[data-loupe-redact]` regions are painted over **before any pixels leave the browser**. |
|
|
62
|
+
| 🧩 **Shadow-DOM isolation** | The widget's CSS never leaks into your page and vice-versa. |
|
|
63
|
+
| 🔌 **Pluggable storage** | Talks to the Loupe backend, or persists to `localStorage` for offline/demo use. |
|
|
64
|
+
| 🤖 **Claude-ready** | Every comment carries the element HTML + computed styles + screenshot Claude Code needs to make the fix. |
|
|
37
65
|
|
|
38
66
|
## Install
|
|
39
67
|
|
|
@@ -41,8 +69,8 @@ the UI changes underneath it.
|
|
|
41
69
|
npm i @loupekit/sdk
|
|
42
70
|
```
|
|
43
71
|
|
|
44
|
-
> Also mirrored to **GitHub Packages** as `@mohamed-ashraf-elsaed/sdk
|
|
45
|
-
>
|
|
72
|
+
> Also mirrored to **GitHub Packages** as `@mohamed-ashraf-elsaed/sdk` — add
|
|
73
|
+
> `@mohamed-ashraf-elsaed:registry=https://npm.pkg.github.com` to your `.npmrc` to install from there.
|
|
46
74
|
|
|
47
75
|
## Quick start
|
|
48
76
|
|
|
@@ -53,37 +81,51 @@ init({
|
|
|
53
81
|
projectKey: "pk_live_yourkey",
|
|
54
82
|
user: { id: "u_92", name: "Sara (PM)", email: "sara@acme.com" },
|
|
55
83
|
apiBase: "https://loupe.yourbackend.com",
|
|
56
|
-
// HMAC-SHA256(user.id, PROJECT_SECRET), computed on your server (see Auth
|
|
84
|
+
// HMAC-SHA256(user.id, PROJECT_SECRET), computed on your server (see Auth model).
|
|
57
85
|
userHmac: "decb2c…",
|
|
58
86
|
});
|
|
59
87
|
```
|
|
60
88
|
|
|
61
|
-
|
|
62
|
-
|
|
89
|
+
A floating toolbar appears with **Inspect & comment**, **Region shot**, and **Comments**.
|
|
90
|
+
Call `destroy()` to tear it down. `init()` is idempotent — safe to call more than once.
|
|
63
91
|
|
|
64
92
|
### Offline mode (no backend)
|
|
65
93
|
|
|
66
|
-
Omit `apiBase` and comments persist to `localStorage
|
|
94
|
+
Omit `apiBase` and comments persist to `localStorage` — great for demos and local dev:
|
|
67
95
|
|
|
68
96
|
```ts
|
|
69
97
|
init({ projectKey: "pk_demo", user: { id: "u_1", name: "You" } });
|
|
70
98
|
```
|
|
71
99
|
|
|
100
|
+
## Re-anchoring across redeploys
|
|
101
|
+
|
|
102
|
+
The crown jewel. A comment records a multi-signal fingerprint of its target. On the next
|
|
103
|
+
page load — even after the UI is rebuilt, relabeled, or reordered — Loupe re-locates the
|
|
104
|
+
element and moves the pin to it. Below, the "Revenue" card was relabeled to "Total Revenue"
|
|
105
|
+
and reordered, yet the pin follows it:
|
|
106
|
+
|
|
107
|
+
<table>
|
|
108
|
+
<tr>
|
|
109
|
+
<td width="50%" align="center"><b>Before redeploy</b><br /><img src="https://raw.githubusercontent.com/mohamed-ashraf-elsaed/loupe/main/docs/before-redeploy.png" alt="Comment pinned to the revenue card" /></td>
|
|
110
|
+
<td width="50%" align="center"><b>After redeploy</b><br /><img src="https://raw.githubusercontent.com/mohamed-ashraf-elsaed/loupe/main/docs/after-redeploy.png" alt="Pin re-anchored after the layout changed" /></td>
|
|
111
|
+
</tr>
|
|
112
|
+
</table>
|
|
113
|
+
|
|
72
114
|
## Configuration
|
|
73
115
|
|
|
74
116
|
`init(config: LoupeConfig)`:
|
|
75
117
|
|
|
76
|
-
| Option
|
|
77
|
-
|
|
|
78
|
-
| `projectKey`
|
|
79
|
-
| `user`
|
|
80
|
-
| `apiBase`
|
|
81
|
-
| `userHmac`
|
|
82
|
-
| `autoOpen`
|
|
83
|
-
| `captureScreenshot
|
|
84
|
-
| `captureRegion`
|
|
85
|
-
| `headers`
|
|
86
|
-
| `credentials`
|
|
118
|
+
| Option | Type | Description |
|
|
119
|
+
| --- | --- | --- |
|
|
120
|
+
| `projectKey` | `string` **(required)** | Public project key issued by the backend. |
|
|
121
|
+
| `user` | `{ id, name, email? }` **(required)** | The already-authenticated host-app user. |
|
|
122
|
+
| `apiBase` | `string` | Backend base URL. Omit → `localStorage` (offline mode). |
|
|
123
|
+
| `userHmac` | `string` | `HMAC-SHA256(user.id, PROJECT_SECRET)` computed server-side. Required in production for writes. |
|
|
124
|
+
| `autoOpen` | `boolean` | Start with the inspector already active. |
|
|
125
|
+
| `captureScreenshot` | `(el: Element) => Promise<string \| undefined>` | Override element screenshot capture (the extension backs this with `captureVisibleTab`). |
|
|
126
|
+
| `captureRegion` | `(rect: RegionRect) => Promise<string \| undefined>` | Override free-region capture. `rect` is in viewport coordinates. |
|
|
127
|
+
| `headers` | `Record<string, string>` | Extra headers merged into every backend request (e.g. a CSRF token). |
|
|
128
|
+
| `credentials` | `RequestCredentials` | `credentials` mode for backend requests — set `"include"` for cross-origin cookie auth. |
|
|
87
129
|
|
|
88
130
|
## Redaction
|
|
89
131
|
|
|
@@ -99,9 +141,9 @@ ever leave the browser** — use it on PII, secrets, or anything sensitive:
|
|
|
99
141
|
Each project has a secret. **Writes** require `X-Loupe-User` + `X-Loupe-Hmac`
|
|
100
142
|
(`= HMAC-SHA256(userId, PROJECT_SECRET)`), which your server computes and injects into the
|
|
101
143
|
page — users can't spoof identity. The dashboard and MCP server authenticate as admin with
|
|
102
|
-
the raw secret.
|
|
144
|
+
the raw secret.
|
|
103
145
|
|
|
104
|
-
##
|
|
146
|
+
## Storage seam
|
|
105
147
|
|
|
106
148
|
Anything implementing `StorageAdapter` can back the widget — swap in your own transport:
|
|
107
149
|
|
|
@@ -114,16 +156,29 @@ interface StorageAdapter {
|
|
|
114
156
|
}
|
|
115
157
|
```
|
|
116
158
|
|
|
117
|
-
##
|
|
159
|
+
## The loop
|
|
118
160
|
|
|
119
|
-
|
|
120
|
-
and
|
|
161
|
+
SDK (in your product) → backend API → Postgres + object storage → **dashboard** (human triage)
|
|
162
|
+
**and** **MCP server** (Claude reads it) → status flows back.
|
|
163
|
+
|
|
164
|
+
<table>
|
|
165
|
+
<tr>
|
|
166
|
+
<td width="50%" align="center"><b>Triage board (dashboard)</b><br /><img src="https://raw.githubusercontent.com/mohamed-ashraf-elsaed/loupe/main/docs/store/screenshot-2-board.jpg" alt="Kanban triage board" /></td>
|
|
167
|
+
<td width="50%" align="center"><b>Claude Code reads it via MCP</b><br /><img src="https://raw.githubusercontent.com/mohamed-ashraf-elsaed/loupe/main/docs/store/screenshot-3-claude.jpg" alt="Claude Code reading comments through MCP" /></td>
|
|
168
|
+
</tr>
|
|
169
|
+
</table>
|
|
121
170
|
|
|
122
171
|
## Related packages
|
|
123
172
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
173
|
+
| Package | Description |
|
|
174
|
+
| --- | --- |
|
|
175
|
+
| [`@loupekit/mcp`](https://www.npmjs.com/package/@loupekit/mcp) | MCP server that hands the comments to Claude Code. |
|
|
176
|
+
| [`@loupekit/shared`](https://www.npmjs.com/package/@loupekit/shared) | The canonical TypeScript types shared across the platform. |
|
|
177
|
+
|
|
178
|
+
## Browser support
|
|
179
|
+
|
|
180
|
+
Modern evergreen browsers (Chromium, Firefox, Safari). Uses Shadow DOM, `MutationObserver`,
|
|
181
|
+
and the `crypto` / `clipboard` APIs.
|
|
127
182
|
|
|
128
183
|
## License
|
|
129
184
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loupekit/sdk",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1-next.3",
|
|
4
4
|
"description": "Embeddable visual-feedback layer: pin comments to the live UI and hand them to Claude.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -12,19 +12,34 @@
|
|
|
12
12
|
"import": "./dist/index.js"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
|
-
"files": [
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
16
18
|
"scripts": {
|
|
17
19
|
"build": "tsup",
|
|
18
20
|
"dev": "tsup --watch",
|
|
19
21
|
"typecheck": "tsc --noEmit"
|
|
20
22
|
},
|
|
21
|
-
"keywords": [
|
|
23
|
+
"keywords": [
|
|
24
|
+
"feedback",
|
|
25
|
+
"annotation",
|
|
26
|
+
"visual-feedback",
|
|
27
|
+
"product-management",
|
|
28
|
+
"claude",
|
|
29
|
+
"mcp"
|
|
30
|
+
],
|
|
22
31
|
"license": "MIT",
|
|
23
|
-
"repository": {
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/mohamed-ashraf-elsaed/loupe.git",
|
|
35
|
+
"directory": "packages/sdk"
|
|
36
|
+
},
|
|
24
37
|
"homepage": "https://mohamed-ashraf-elsaed.github.io/loupe/",
|
|
25
|
-
"publishConfig": {
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
26
41
|
"devDependencies": {
|
|
27
|
-
"@loupekit/shared": "
|
|
42
|
+
"@loupekit/shared": "0.2.1-next.3",
|
|
28
43
|
"modern-screenshot": "^4.6.6"
|
|
29
44
|
}
|
|
30
45
|
}
|