@insitue/sdk 0.2.0 → 0.3.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/README.md ADDED
@@ -0,0 +1,203 @@
1
+ # `@insitue/sdk`
2
+
3
+ The InSitue capture widget for browser apps. One component,
4
+ two sinks: ship captures to the InSitue Cloud (production
5
+ bug-reporting → autopilot → draft PR) or to a local
6
+ `@insitue/companion` (developer mode → `claude` in your terminal
7
+ acts on each pick).
8
+
9
+ ```tsx
10
+ import { InSitueCapture } from "@insitue/sdk";
11
+
12
+ // Dev: companion sink (no projectKey).
13
+ <InSitueCapture />
14
+
15
+ // Prod: cloud sink with your publishable project key.
16
+ <InSitueCapture projectKey="pk_..." />
17
+ ```
18
+
19
+ Same widget. Same picker. Same screenshot pipeline. Only the
20
+ submit step changes.
21
+
22
+ ---
23
+
24
+ ## Install
25
+
26
+ ```bash
27
+ npm install -D @insitue/sdk
28
+ # or pnpm add -D @insitue/sdk
29
+ # or yarn add -D @insitue/sdk
30
+ ```
31
+
32
+ ## Dev mode (talk to claude in your terminal)
33
+
34
+ Mount with no props. The widget connects to a local companion
35
+ over a loopback WebSocket. A `claude` session running
36
+ [`/insitue:connect`](https://www.npmjs.com/package/@insitue/claude-plugin)
37
+ picks up each capture and edits the file you pointed at.
38
+
39
+ ```tsx
40
+ // app/layout.tsx (Next.js) — dev-gated so the chunk never
41
+ // ships in production.
42
+ import { InSitueCapture } from "@insitue/sdk";
43
+
44
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
45
+ return (
46
+ <html>
47
+ <body>
48
+ {children}
49
+ {process.env.NODE_ENV !== "production" && <InSitueCapture />}
50
+ </body>
51
+ </html>
52
+ );
53
+ }
54
+ ```
55
+
56
+ ```tsx
57
+ // src/main.tsx (Vite)
58
+ import { InSitueCapture } from "@insitue/sdk";
59
+
60
+ createRoot(document.getElementById("root")!).render(
61
+ <StrictMode>
62
+ <App />
63
+ {import.meta.env.DEV && <InSitueCapture />}
64
+ </StrictMode>,
65
+ );
66
+ ```
67
+
68
+ ## Production mode (cloud sink → autopilot → draft PR)
69
+
70
+ Pass your publishable `projectKey` (e.g. `pk_…`). The key is
71
+ Origin-pinned and quota-gated server-side, so it's safe to ship
72
+ in a public bundle.
73
+
74
+ ```tsx
75
+ <InSitueCapture projectKey={process.env.NEXT_PUBLIC_INSITUE_KEY!} />
76
+ ```
77
+
78
+ End users see a friendly "Report a problem" pill in the corner
79
+ of your app. Clicking it activates the picker; describing +
80
+ sending submits to your InSitue inbox.
81
+
82
+ ---
83
+
84
+ ## Props
85
+
86
+ ```ts
87
+ interface InSitueCaptureProps {
88
+ /** Publishable project key. Set → cloud sink. */
89
+ projectKey?: string;
90
+ /** Override the cloud ingest endpoint. */
91
+ endpoint?: string;
92
+ /** Take over delivery yourself. Wins over both projectKey
93
+ * and sink. */
94
+ onCapture?: (draft: IssueDraft, bundle: CaptureBundle) => void;
95
+ /** Explicit sink override (rarely needed — most callers rely
96
+ * on auto-detection). */
97
+ sink?: CaptureSink;
98
+ /** Force getDisplayMedia capture from mount. Dev/dogfood only. */
99
+ defaultPixelPerfect?: boolean;
100
+ }
101
+ ```
102
+
103
+ ## Sink auto-detection
104
+
105
+ | `projectKey` | `sink` | Result |
106
+ |---|---|---|
107
+ | set | unset | Cloud sink (post to InSitue Cloud) |
108
+ | unset | unset | Companion sink (post to local WS, default port `5747`) |
109
+ | any | set | Use `sink` verbatim |
110
+
111
+ `onCapture` wins over everything when defined.
112
+
113
+ ---
114
+
115
+ ## Bulletproof selection
116
+
117
+ Every pick the widget submits has a usable source location.
118
+ The picker walks React fiber `_debugSource` first (exact), then
119
+ the `data-insitu-source` attribute injected by
120
+ [`@insitue/sdk/babel`](#babel-plugin) (exact), then the nearest
121
+ owning component's source (approximate). If even that fails,
122
+ the widget refuses to send and asks the user to pick a parent
123
+ — claude never gets a meaningless selector-only pick.
124
+
125
+ The confidence chip is shown inline so users (and you, in
126
+ testing) can see exactly what's been resolved before they hit
127
+ Send.
128
+
129
+ ## Babel plugin
130
+
131
+ Optional — only needed when your bundler doesn't expose React
132
+ fiber `_debugSource` (Vite, some Webpack setups). Adds a
133
+ `data-insitu-source="file:line:col"` attribute to every
134
+ intrinsic JSX element so source resolution stays exact.
135
+
136
+ ```js
137
+ // vite.config.ts
138
+ import insituBabel from "@insitue/sdk/babel";
139
+
140
+ export default {
141
+ plugins: [
142
+ react({
143
+ babel: {
144
+ plugins: [[insituBabel, { root: __dirname }]],
145
+ },
146
+ }),
147
+ ],
148
+ };
149
+ ```
150
+
151
+ The `root` must match the project directory the companion is
152
+ scoped to (typically `__dirname` of `vite.config.ts`).
153
+
154
+ ---
155
+
156
+ ## What's in a capture
157
+
158
+ Every send produces a `CaptureBundle`:
159
+
160
+ ```ts
161
+ interface CaptureBundle {
162
+ id: string; // unique per capture
163
+ target: { source, confidence, selector, componentStack };
164
+ screenshot?: { dataUrl, source: "rasterise" | "display-media" };
165
+ computedStyles: Record<string, string>;
166
+ tailwindClasses: string[];
167
+ userNote?: string; // the user's description
168
+ runtime: { url, route, console, network, errors };
169
+ viewport: { w, h, dpr, breakpoint };
170
+ }
171
+ ```
172
+
173
+ Cloud sink: this goes to `https://www.insitue.com/api/v1/capture`
174
+ with your `projectKey`. Companion sink: it goes to
175
+ `ws://127.0.0.1:5747` (the local companion's loopback WS) which
176
+ broadcasts to subscribed CLI/MCP listeners.
177
+
178
+ ---
179
+
180
+ ## Going to production
181
+
182
+ The same `<InSitueCapture />` works in both modes — just pass
183
+ `projectKey` in production and your users get the SaaS theme
184
+ (warm, friendly) instead of the dev theme (dark, terminal-flavour).
185
+ A typical setup:
186
+
187
+ ```tsx
188
+ const PROJECT_KEY = process.env.NEXT_PUBLIC_INSITUE_KEY;
189
+ const IS_PROD = process.env.NODE_ENV === "production";
190
+
191
+ export default function InSitueWidget() {
192
+ if (IS_PROD && !PROJECT_KEY) return null;
193
+ return IS_PROD ? <InSitueCapture projectKey={PROJECT_KEY} /> : <InSitueCapture />;
194
+ }
195
+ ```
196
+
197
+ Then drop `<InSitueWidget />` once in your app root.
198
+
199
+ ---
200
+
201
+ ## License
202
+
203
+ MIT.
@@ -1,37 +1,47 @@
1
1
  import { IssueDraft, CaptureBundle } from '@insitue/capture-core';
2
2
 
3
+ /** Where captures go. Auto-detected from `projectKey` if omitted. */
4
+ type CaptureSink = {
5
+ kind: "cloud";
6
+ projectKey: string;
7
+ endpoint?: string;
8
+ } | {
9
+ kind: "companion";
10
+ port?: number;
11
+ };
3
12
  interface CaptureOnlyOptions {
4
13
  /**
5
14
  * Publishable project key (e.g. `pk_…`). When set, captures POST
6
- * to the InSitue cloud automatically — no `onCapture` plumbing
7
- * required. The key is publishable (Origin-pinned + quota-gated
8
- * server-side) so it's safe to ship in your production bundle.
15
+ * to the InSitue cloud automatically — implies `sink: { kind:
16
+ * "cloud", projectKey }`. The key is publishable (Origin-pinned +
17
+ * quota-gated server-side) so it's safe to ship in production.
9
18
  */
10
19
  projectKey?: string;
11
- /**
12
- * Ingest endpoint. Defaults to the InSitue cloud. Override only if
13
- * you self-host the ingest service or proxy it from your own
14
- * origin.
15
- */
20
+ /** Ingest endpoint (cloud sink). Defaults to the InSitue cloud. */
16
21
  endpoint?: string;
17
22
  /**
18
- * Take over delivery yourself. Wins over `projectKey` if both are
19
- * set. Default (neither set): console + JSON download +
20
- * `window.__insitu_capture__` (useful for prod validation).
23
+ * Take over delivery yourself. Wins over `projectKey` AND `sink`.
24
+ * Default (neither set + no companion reachable): console + JSON
25
+ * download + `window.__insitu_capture__` (useful for prod
26
+ * validation).
21
27
  */
22
28
  onCapture?: (draft: IssueDraft, bundle: CaptureBundle) => void;
29
+ /**
30
+ * Override the sink explicitly. Use when auto-detection isn't
31
+ * right — e.g. you set a `projectKey` but want to ship to a local
32
+ * companion for testing. Most callers leave this undefined.
33
+ */
34
+ sink?: CaptureSink;
23
35
  /**
24
36
  * Force the pixel-perfect (`getDisplayMedia`) path for every
25
37
  * capture from mount. Costs a one-time tab-share permission per
26
38
  * session in exchange for screenshots that are guaranteed to
27
39
  * match what the user actually saw — bypasses every html-to-image
28
- * quirk (next/image srcset, video frames, canvas content,
29
- * cross-origin assets). Use in dev/dogfood where capture quality
30
- * matters more than permission UX; leave off for prod end-users
31
- * who shouldn't see a permission dialog uninvited.
40
+ * quirk. Use in dev/dogfood where capture quality matters more
41
+ * than the permission UX.
32
42
  */
33
43
  defaultPixelPerfect?: boolean;
34
44
  }
35
45
  declare function mountCaptureOnly(opts?: CaptureOnlyOptions): () => void;
36
46
 
37
- export { type CaptureOnlyOptions, mountCaptureOnly };
47
+ export { type CaptureOnlyOptions, type CaptureSink, mountCaptureOnly };
@@ -1,7 +1,6 @@
1
1
  import {
2
2
  mountCaptureOnly
3
- } from "./chunk-ZV3AVYBI.js";
4
- import "./chunk-62N4L6RA.js";
3
+ } from "./chunk-YU5T67XL.js";
5
4
  export {
6
5
  mountCaptureOnly
7
6
  };