@fastbackr/react 0.0.0-stage → 0.0.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/LICENSE ADDED
@@ -0,0 +1,46 @@
1
+ Fastbackr SDK License
2
+
3
+ Copyright (c) 2026 OpsCom, Corp. All rights reserved.
4
+
5
+ This license covers the "@fastbackr/react" npm package and its source code (the
6
+ "Software"). The Software is not open source. By installing or using it you
7
+ accept these terms.
8
+
9
+ 1. Grant. OpsCom, Corp. grants you a free, non-exclusive, non-transferable,
10
+ non-sublicensable license to install and use the Software, solely to connect
11
+ your websites and applications to the Fastbackr service.
12
+
13
+ 2. Redistribution. You may redistribute the Software only unmodified and only
14
+ as part of your own website or application. Bundling, minifying,
15
+ transpiling or tree-shaking the Software with your build tools, as part of
16
+ building your own website or application, is not a modification under
17
+ this license.
18
+
19
+ 3. Restrictions. Except as section 2 allows, you may not:
20
+ a. modify, adapt or translate the Software, or create derivative works of
21
+ it;
22
+ b. distribute, publish or make available any modified version of the
23
+ Software;
24
+ c. use the Software with any service other than the Fastbackr service;
25
+ d. sell, rent, lease or sublicense the Software on its own;
26
+ e. remove or alter this license or any copyright notice;
27
+ f. reverse engineer, decompile or disassemble the Software, except to the
28
+ extent applicable law expressly permits it despite this restriction.
29
+
30
+ 4. Ownership. The Software is licensed, not sold. OpsCom, Corp. keeps all
31
+ rights, title and interest in the Software not expressly granted here.
32
+
33
+ 5. Termination. This license ends automatically if you breach any of its
34
+ terms. On termination you must stop using the Software and remove it from
35
+ your websites and applications.
36
+
37
+ 6. No warranty. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
38
+ EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR
39
+ A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
40
+
41
+ 7. Limitation of liability. IN NO EVENT SHALL OPSCOM, CORP. BE LIABLE FOR ANY
42
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
43
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
44
+ OF OR OTHER DEALINGS IN THE SOFTWARE.
45
+
46
+ 8. Governing law. This license is governed by the laws of the United States.
package/README.md CHANGED
@@ -1,3 +1,217 @@
1
- # Temporary Holding Version
1
+ # @fastbackr/react
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Let reviewers click any element of your React app, or drag a box around any area, and leave a
4
+ comment on it. Comments show as numbered badges on the element or area, with replies, Done / Reopen
5
+ and a site-wide drawer.
6
+
7
+ - **One provider.** Wrap your app in `<FastbackrProvider>`. The UI is drawn inside a Shadow root with its own
8
+ stylesheet, so your CSS and ours never touch, whatever your app styles with.
9
+ - **Quiet until clicked.** A page view shows a small `+` button in the bottom-right corner, adds
10
+ two listeners and makes no requests. The first click on `+` loads the UI as a separate chunk.
11
+ - **Your app vouches for identity.** Your server trades its API key for a short-lived reviewer token.
12
+ The key never reaches a browser.
13
+
14
+ ## Install
15
+
16
+ ```sh
17
+ npm install @fastbackr/react @fastbackr/core
18
+ ```
19
+
20
+ React 19 is a peer dependency. `@fastbackr/react` is the browser side; your server imports
21
+ `@fastbackr/core`:
22
+
23
+ | Import | Runs in | What it is |
24
+ | ------------------------ | ----------- | ------------------------------------------------------- |
25
+ | `@fastbackr/react` | Browser | `<FastbackrProvider>`, `useFastbackr()` |
26
+ | `@fastbackr/core/server` | Your server | `createTokenHandler`, `createReviewerToken`, the errors |
27
+
28
+ ## Setup
29
+
30
+ You need a Fastbackr project and its API key (v1: created in the Fastbackr dashboard), with your site's
31
+ origins on the project's allowed list (`http://localhost:*` style patterns are fine).
32
+
33
+ ### 1. Keep the API key on the server
34
+
35
+ ```sh
36
+ # .env (server only)
37
+ FASTBACKR_API_KEY=fb_...
38
+ # Optional, for a self-hosted or local API. Defaults to https://api.fastbackr.com
39
+ FASTBACKR_URL=http://localhost:3300
40
+ ```
41
+
42
+ **`FASTBACKR_API_KEY` must never reach a browser.** Do not prefix it with `NEXT_PUBLIC_`, `VITE_` or
43
+ anything else that inlines it into client code, do not return it from a route, and do not log it.
44
+ Anyone holding it can mint tokens for any name on your project.
45
+
46
+ ### 2. Add the token route
47
+
48
+ The SDK asks this route on your own origin for a short-lived reviewer token, so your session cookie
49
+ stays first-party. `createTokenHandler` reads the key from `FASTBACKR_API_KEY`, decides who the
50
+ reviewer is and answers the SDK. Next.js App Router:
51
+
52
+ ```ts
53
+ // app/api/fastbackr/route.ts
54
+ import { createTokenHandler } from '@fastbackr/core/server';
55
+ import { auth } from '@/lib/auth'; // your own auth
56
+
57
+ export const POST = createTokenHandler({
58
+ // Optional: who is signed in. Leave it out and everyone comments as a guest.
59
+ getUser: async () => {
60
+ const session = await auth();
61
+ return session && { id: session.user.id, name: session.user.name, email: session.user.email };
62
+ },
63
+ });
64
+ ```
65
+
66
+ The handler takes a web `Request` and returns a `Response`, so it is the route as-is in React
67
+ Router, Hono, SvelteKit, Bun, Deno and Workers too. `getUser` gets the request. When it names
68
+ nobody, a visitor who typed a name gets a guest token (id `guest:<random id>`, `verified: false`),
69
+ so a guest can never claim a signed-in user's id; anyone else gets 401 and the SDK asks for a name.
70
+
71
+ ### 3. Wrap your app
72
+
73
+ ```tsx
74
+ // app/layout.tsx
75
+ import { FastbackrProvider } from '@fastbackr/react';
76
+
77
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
78
+ return (
79
+ <html lang="en">
80
+ <body>
81
+ <FastbackrProvider>{children}</FastbackrProvider>
82
+ </body>
83
+ </html>
84
+ );
85
+ }
86
+ ```
87
+
88
+ The provider is a client component that Server Components can render. Only one SDK runs per page,
89
+ so React Strict Mode and a second provider are fine.
90
+
91
+ ### 4. Allow the API in your Content-Security-Policy
92
+
93
+ If your site sends a CSP, add the API to `connect-src`:
94
+
95
+ ```text
96
+ Content-Security-Policy: connect-src 'self' https://api.fastbackr.com
97
+ ```
98
+
99
+ When the policy blocks the API, the SDK logs one console error naming the directive to add.
100
+
101
+ ## Using it
102
+
103
+ - Click `+` (or press `c` once the bar is open). The cursor becomes a crosshair: click an element, or
104
+ drag a box around an area, then write in the box that opens below it. On touch screens, tap an
105
+ element.
106
+ - The bar stays for the rest of the tab's session. Its chevron (Minimize) goes back to the `+`
107
+ button. Its ✕ (Close) removes the `+` button too, in this browser; press `f` three times
108
+ (outside a text field) to bring it back. `useFastbackr().show()` does the same from code.
109
+ - `Feedback` opens the drawer with every thread on the site, filtered by status and page.
110
+ - A box is stored as a fraction of the element it sits on, so it follows that element at other
111
+ screen widths. When the element's shape changes a lot (columns stacked on a phone), the whole
112
+ element is outlined and the thread names the width the comment was left at.
113
+
114
+ ## Options
115
+
116
+ `<FastbackrProvider>` props:
117
+
118
+ | Prop | Type | Default |
119
+ | ---------------- | ------------------------------------ | --------------------------- |
120
+ | `tokenUrl` | `string` | `/api/fastbackr` |
121
+ | `getToken` | `(guest?) => Promise<Token \| null>` | asks `tokenUrl` |
122
+ | `endpoint` | `string` | `https://api.fastbackr.com` |
123
+ | `signIn` | `() => void \| Promise<void>` | none: no "Sign in" button |
124
+ | `queryKeys` | `readonly string[]` | `[]` |
125
+ | `hashRoutes` | `boolean` | `false` |
126
+ | `getPageContext` | `() => { key, path, title }` | built from the URL |
127
+
128
+ - `getToken` replaces the request to `tokenUrl`, for a token route of your own. With no arguments
129
+ it asks "who is signed in?". With `guest` (`{ id, name }`) a guest typed their name; `guest.id` is
130
+ random, generated once and kept in `localStorage`. Resolve `{ token, expiresAt, user }`, or `null`
131
+ for "not signed in". A rejection's message is shown.
132
+ - The SDK refreshes the token a minute before it expires and after any 401.
133
+ - `useFastbackr()`, inside the provider, returns `show()` and `hide()` for your own buttons. `show()`
134
+ brings back a closed `+` button and sends a rainbow ring around it (or around the open bar) for 2s.
135
+ `hide()` is the same as Close.
136
+ - `hashRoutes: true` makes `#records/12` a distinct page. Credential-looking query keys (`token`,
137
+ `secret` and similar) never enter a page key, even when listed.
138
+
139
+ ## Guests
140
+
141
+ Without a signed-in session the bar asks for a name, or "Anonymously" (the name `Anonymous`), and,
142
+ when you passed `signIn`, shows a "Sign in" button. A guest's name carries a "guest" tag in threads and the drawer list; in the bar, a guest clicks their
143
+ name to change it.
144
+
145
+ What a guest may do is a per-project setting on the server:
146
+
147
+ | Guest access | Effect |
148
+ | ------------ | ------------------------------------------------------------------- |
149
+ | `off` | `/v1/tokens` refuses `verified: false` (403 `guest_access_off`) |
150
+ | `write-only` | A guest sees, replies to and resolves only the threads they created |
151
+ | `read-write` | A guest is treated like a signed-in reviewer |
152
+
153
+ Use `write-only` when guests are outsiders (customers, prospects) who must not read your team's
154
+ comments.
155
+
156
+ ## Screenshots
157
+
158
+ Turn on Screenshots in the project's settings in the dashboard (off by default) and each new thread
159
+ gets an image of the reviewer's viewport, taken on Save, with the commented element outlined. It
160
+ shows above the first message. The reviewer can uncheck "Take screenshot" in the comment box to skip
161
+ it for that comment. Fastbackr's own UI is left out, and `data-fastbackr-private`
162
+ elements and form fields (text inputs, textareas, selects, editable regions) become black boxes.
163
+ Everything else on screen is captured, customer data included: mark private areas with
164
+ `data-fastbackr-private`. The panel shows the image from a `blob:` URL, so a CSP needs
165
+ `img-src blob:`.
166
+
167
+ ## Marking up your page (optional)
168
+
169
+ Comments find their element again from its tag, label, text and position. Ids that look generated
170
+ (`:r1:`, `radix-12`, hashed names) are ignored. Explicit ids are sturdier:
171
+
172
+ | Attribute | Effect |
173
+ | -------------------------------- | ------------------------------------------------------------- |
174
+ | `data-fastbackr-id="hero-cta"` | Stable identity; a comment attaches to exactly this element |
175
+ | `data-fastbackr-component="Nav"` | Labels comments left on this element |
176
+ | `data-fastbackr-private` | Never in a comment's excerpt; a black box in screenshots |
177
+
178
+ Form field values are never captured, and screenshots black the fields out.
179
+
180
+ ## A token route in another language
181
+
182
+ `createTokenHandler` is the easy path. Any server can answer the SDK instead (Express, Rails,
183
+ Django, Go): `POST /api/fastbackr` on your origin receives `{}` ("who is signed in?") or
184
+ `{ "guest": { "id", "name" } }`. Answer:
185
+
186
+ - 200 with the body of `POST https://api.fastbackr.com/v1/tokens`, which you call with
187
+ `Authorization: Bearer <FASTBACKR_API_KEY>` and `{ "user": { "id", "name", "email"?, "verified" } }`.
188
+ Vouch for a guest as `{ "id": "guest:<guest.id>", "name": <guest.name>, "verified": false }`.
189
+ - 401 when nobody may comment yet: the SDK shows its name form.
190
+ - 403 `{ "error": { "code": "guest_access_off", ... } }` passed on from the API.
191
+
192
+ In Node, `createReviewerToken({ apiKey, user })` makes that API call for you.
193
+
194
+ ## Errors on the server
195
+
196
+ `createTokenHandler` answers errors itself (500 when `FASTBACKR_API_KEY` is missing, 502 when the
197
+ API cannot be reached) and logs the reason. `createReviewerToken` throws `FastbackrError` with
198
+ `status` and `code`:
199
+
200
+ - `status: 0`, `invalid_request`: bad input; nothing was sent.
201
+ - `status: 0`, `network_error`: the API could not be reached.
202
+ - otherwise the API's own status and code, for example `401 unauthorized` (bad or revoked key),
203
+ `403 guest_access_off`.
204
+
205
+ Error messages never include the API key.
206
+
207
+ ## How it is built
208
+
209
+ `@fastbackr/core` holds the logic: tokens, the API client, finding an element again, select mode.
210
+ This package draws the UI with the components and theme of Fastbackr's design system (shadcn on
211
+ Base UI, Tailwind CSS v4). The build compiles that stylesheet and the SDK injects it into its
212
+ Shadow root; your page never loads it. Browsers ignore `@property` inside a Shadow root, so the build
213
+ turns on Tailwind's fallback values for its `--tw-*` variables instead. The UI uses the system font.
214
+
215
+ ## License
216
+
217
+ Free to install and use with the Fastbackr service. Modifying it is not allowed. See `LICENSE`.