@beezping/adapter-memory 0.6.0 → 0.7.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.
- package/LICENSE +21 -0
- package/README.md +10 -8
- package/dist/beezping-core.d.cts +20 -0
- package/dist/beezping-core.d.ts +20 -0
- package/dist/concurrency.d.cts +14 -0
- package/dist/concurrency.d.ts +14 -0
- package/dist/constants/schema.d.cts +239 -0
- package/dist/constants/schema.d.ts +239 -0
- package/dist/deep-link.d.cts +14 -0
- package/dist/deep-link.d.ts +14 -0
- package/dist/email.d.cts +8 -5
- package/dist/email.d.ts +8 -5
- package/dist/errors.d.cts +28 -14
- package/dist/errors.d.ts +28 -14
- package/dist/filters.d.cts +15 -7
- package/dist/filters.d.ts +15 -7
- package/dist/i18n.d.cts +18 -0
- package/dist/i18n.d.ts +18 -0
- package/dist/index.cjs +99 -61
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -7
- package/dist/index.d.ts +9 -7
- package/dist/index.js +99 -61
- package/dist/index.js.map +1 -1
- package/dist/schema.d.cts +12 -195
- package/dist/schema.d.ts +12 -195
- package/dist/screenshot-storage.d.cts +55 -30
- package/dist/screenshot-storage.d.ts +55 -30
- package/dist/store-helpers.d.cts +62 -34
- package/dist/store-helpers.d.ts +62 -34
- package/dist/type-utils.d.cts +8 -0
- package/dist/type-utils.d.ts +8 -0
- package/dist/types.d.cts +413 -154
- package/dist/types.d.ts +413 -154
- package/dist/wire.d.cts +42 -9
- package/dist/wire.d.ts +42 -9
- package/package.json +7 -8
- package/dist/siteping-core.d.cts +0 -17
- package/dist/siteping-core.d.ts +0 -17
package/dist/types.d.ts
CHANGED
|
@@ -1,96 +1,152 @@
|
|
|
1
|
-
import { type Prettify, type Serialized } from "./type-utils.js";
|
|
1
|
+
import { type DeepReadonly, type Prettify, type Serialized } from "./type-utils.js";
|
|
2
2
|
/** FAB anchor — bottom-corner placement supported by the widget. */
|
|
3
|
-
export type
|
|
3
|
+
export type BeezpingPosition = "bottom-right" | "bottom-left";
|
|
4
4
|
/** Visual theme — `auto` resolves to `light` or `dark` via system preference. */
|
|
5
|
-
export type
|
|
5
|
+
export type BeezpingTheme = "light" | "dark" | "auto";
|
|
6
6
|
/** Built-in UI locales shipped with the widget. */
|
|
7
|
-
export declare const BUILTIN_LOCALES: readonly ["en", "fr", "de", "es", "it", "pt", "ru"];
|
|
7
|
+
export declare const BUILTIN_LOCALES: readonly ["en", "fr", "de", "es", "it", "pt", "ru", "ja"];
|
|
8
8
|
export type BuiltinLocale = (typeof BUILTIN_LOCALES)[number];
|
|
9
9
|
/**
|
|
10
10
|
* Locale identifier accepted by the widget. Built-in locales are kept as
|
|
11
11
|
* literal strings so editors auto-complete them, but arbitrary BCP-47 tags
|
|
12
12
|
* are also accepted (custom dictionaries registered via `registerLocale`).
|
|
13
13
|
*/
|
|
14
|
-
export type
|
|
14
|
+
export type BeezpingLocale = BuiltinLocale | (string & {});
|
|
15
15
|
/**
|
|
16
|
-
* Reasons reported through `
|
|
17
|
-
*
|
|
16
|
+
* Reasons reported through `BeezpingConfig.onSkip` — production environment,
|
|
17
|
+
* viewport narrower than `minViewportWidth` (`"mobile"`), or server-side
|
|
18
|
+
* rendering (no `window`/`document`).
|
|
18
19
|
*/
|
|
19
|
-
export type
|
|
20
|
+
export type BeezpingSkipReason = "production" | "mobile" | "ssr";
|
|
20
21
|
/** Per-channel + per-buffer-size diagnostics configuration. */
|
|
21
22
|
export interface DiagnosticsCaptureOptions {
|
|
22
23
|
console?: boolean | undefined;
|
|
23
24
|
network?: boolean | undefined;
|
|
25
|
+
/** Console buffer size — default and maximum 50 (the server's cap; larger values are clamped). */
|
|
24
26
|
maxConsoleEntries?: number | undefined;
|
|
27
|
+
/** Failed-request buffer size — default and maximum 20 (the server's cap; larger values are clamped). */
|
|
25
28
|
maxNetworkEntries?: number | undefined;
|
|
26
29
|
}
|
|
27
30
|
/** Identity payload supplied by the host application — bypasses the modal. */
|
|
28
|
-
export interface
|
|
31
|
+
export interface BeezpingIdentity {
|
|
29
32
|
name: string;
|
|
30
33
|
email: string;
|
|
31
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Max length of an identity's `name` and `email` — the HTTP schema's
|
|
37
|
+
* `authorName` / `authorEmail` cap. The widget's modal enforces it so a value
|
|
38
|
+
* it persists is never a 400 on every later submission.
|
|
39
|
+
*/
|
|
40
|
+
export declare const IDENTITY_FIELD_MAX_LENGTH = 200;
|
|
32
41
|
/** Deep-link configuration — controls how a feedback id is read from the URL. */
|
|
33
|
-
export interface
|
|
34
|
-
/** Query parameter name carrying the feedback id. Defaults to `"
|
|
42
|
+
export interface BeezpingDeepLinkOptions {
|
|
43
|
+
/** Query parameter name carrying the feedback id. Defaults to `"beezping"`. */
|
|
35
44
|
param?: string | undefined;
|
|
36
45
|
}
|
|
37
46
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
47
|
+
* The feedback handed to panel action callbacks: a detached, deeply frozen
|
|
48
|
+
* copy, typed read-only all the way down. Type your own helpers with it — a
|
|
49
|
+
* `FeedbackResponse` parameter does not accept the frozen copy.
|
|
41
50
|
*/
|
|
42
|
-
export type
|
|
51
|
+
export type BeezpingPanelActionFeedback = DeepReadonly<FeedbackResponse>;
|
|
43
52
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
export declare const REQUEST_CREDENTIALS_MODES: readonly ["omit", "same-origin", "include"];
|
|
61
|
-
/**
|
|
62
|
-
* Credentials mode used when none is configured — the browser's own `fetch`
|
|
63
|
-
* default, so leaving the option unset never changes cookie behavior (and
|
|
64
|
-
* never opts a cross-origin endpoint into cookie-carrying, CSRF-prone requests).
|
|
65
|
-
*/
|
|
66
|
-
export declare const DEFAULT_REQUEST_CREDENTIALS = "same-origin";
|
|
67
|
-
/**
|
|
68
|
-
* Narrow an untyped config value to a {@link SitepingRequestCredentials} mode.
|
|
53
|
+
* Helpers passed to a panel action's `onAction` as its second argument.
|
|
54
|
+
* Both do nothing once the widget has been destroyed.
|
|
55
|
+
*/
|
|
56
|
+
export interface BeezpingPanelActionContext {
|
|
57
|
+
/**
|
|
58
|
+
* Re-fetch the panel list and markers, then re-render the detail view with
|
|
59
|
+
* the updated feedback — or go back to the list when it no longer matches
|
|
60
|
+
* the panel filters. Call it after your action changed the feedback
|
|
61
|
+
* server-side (e.g. moved it to `in_progress` once a ticket exists).
|
|
62
|
+
*/
|
|
63
|
+
refresh: () => Promise<void>;
|
|
64
|
+
/** Close the feedback panel. */
|
|
65
|
+
close: () => void;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Fields shared by both kinds of {@link BeezpingPanelAction}.
|
|
69
69
|
*
|
|
70
|
-
*
|
|
71
|
-
* @returns `true` when `value` is one of {@link REQUEST_CREDENTIALS_MODES}.
|
|
70
|
+
* Do not use this type directly — use {@link BeezpingPanelAction}.
|
|
72
71
|
*/
|
|
73
|
-
export
|
|
72
|
+
export interface BeezpingPanelActionBase {
|
|
73
|
+
/** Stable, unique identifier — becomes `data-action-id` on the rendered control. */
|
|
74
|
+
id: string;
|
|
75
|
+
/**
|
|
76
|
+
* Visible label, rendered as plain text. Host-provided verbatim — not
|
|
77
|
+
* routed through the widget i18n, since hosts localize their own strings.
|
|
78
|
+
*/
|
|
79
|
+
label: string;
|
|
80
|
+
/**
|
|
81
|
+
* Optional inline SVG markup rendered before the label. It is parsed
|
|
82
|
+
* inertly and reduced to plain shapes — scripts, event handlers, links,
|
|
83
|
+
* styles and external references are dropped — but keep it static markup
|
|
84
|
+
* you control. Markup that is not an `<svg>` is ignored with a warning.
|
|
85
|
+
*/
|
|
86
|
+
icon?: string | undefined;
|
|
87
|
+
/**
|
|
88
|
+
* Per-feedback visibility predicate. Return `false` to omit the action
|
|
89
|
+
* for that feedback. Defaults to always visible. A throw hides the action
|
|
90
|
+
* and is reported through `onError`.
|
|
91
|
+
*/
|
|
92
|
+
visible?: ((feedback: BeezpingPanelActionFeedback) => boolean) | undefined;
|
|
93
|
+
}
|
|
94
|
+
/** A panel action rendered as a button that runs host code. */
|
|
95
|
+
export interface BeezpingPanelButtonAction extends BeezpingPanelActionBase {
|
|
96
|
+
/**
|
|
97
|
+
* Invoked on click. While a returned promise is pending the detail view's
|
|
98
|
+
* action buttons are disabled and the clicked button shows a spinner —
|
|
99
|
+
* also after `context.refresh()` re-renders the view, and when the user
|
|
100
|
+
* comes back to that feedback.
|
|
101
|
+
* Throws and rejections are reported through `onError` and restore the
|
|
102
|
+
* buttons; the detail view stays open either way.
|
|
103
|
+
*/
|
|
104
|
+
onAction: (feedback: BeezpingPanelActionFeedback, context: BeezpingPanelActionContext) => void | Promise<void>;
|
|
105
|
+
/** Not available on a button action — use either `onAction` or `href`, never both. */
|
|
106
|
+
href?: never;
|
|
107
|
+
}
|
|
108
|
+
/** A panel action rendered as a link. */
|
|
109
|
+
export interface BeezpingPanelLinkAction extends BeezpingPanelActionBase {
|
|
110
|
+
/**
|
|
111
|
+
* Link target — a URL, or a function building one from the feedback.
|
|
112
|
+
* Relative URLs resolve against the page. Only `http:`, `https:` and
|
|
113
|
+
* `mailto:` are rendered: a static `href` with any other scheme
|
|
114
|
+
* (`javascript:` included) skips the action with a warning; a function
|
|
115
|
+
* returning one hides the action and is reported through `onError`. Web
|
|
116
|
+
* links open in a new tab with `rel="noopener noreferrer"`.
|
|
117
|
+
*/
|
|
118
|
+
href: string | ((feedback: BeezpingPanelActionFeedback) => string);
|
|
119
|
+
/** Not available on a link action — use either `onAction` or `href`, never both. */
|
|
120
|
+
onAction?: never;
|
|
121
|
+
}
|
|
74
122
|
/**
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
123
|
+
* A host-defined action rendered in the feedback detail view, below the
|
|
124
|
+
* built-in Resolve / Delete buttons: a button running your code
|
|
125
|
+
* (`onAction`) or a link (`href`) — never both.
|
|
78
126
|
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
127
|
+
* Hosts use this to bridge feedbacks into their own systems — create a
|
|
128
|
+
* ticket, dispatch to a bot, open the feedback in their tracker — without
|
|
129
|
+
* forking the panel. Callbacks receive a detached, deeply frozen copy of
|
|
130
|
+
* the feedback: read it freely, it can never alter what the panel displays.
|
|
81
131
|
*/
|
|
82
|
-
export
|
|
132
|
+
export type BeezpingPanelAction = BeezpingPanelButtonAction | BeezpingPanelLinkAction;
|
|
133
|
+
/**
|
|
134
|
+
* Extra request headers for HTTP mode — a static map, or a factory (sync or
|
|
135
|
+
* async) invoked once per request to produce fresh values (e.g. a short-lived
|
|
136
|
+
* session token).
|
|
137
|
+
*/
|
|
138
|
+
export type BeezpingHeadersOption = Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
|
|
83
139
|
/**
|
|
84
140
|
* Options shared by both widget modes (HTTP and direct store).
|
|
85
141
|
*
|
|
86
|
-
* Do not use this type directly — use {@link
|
|
142
|
+
* Do not use this type directly — use {@link BeezpingConfig}, the
|
|
87
143
|
* discriminated union that adds the mode-specific fields.
|
|
88
144
|
*/
|
|
89
|
-
export interface
|
|
145
|
+
export interface BeezpingBaseConfig {
|
|
90
146
|
/** Required — project identifier used to scope feedbacks */
|
|
91
147
|
projectName: string;
|
|
92
148
|
/** FAB position — defaults to 'bottom-right' */
|
|
93
|
-
position?:
|
|
149
|
+
position?: BeezpingPosition | undefined;
|
|
94
150
|
/**
|
|
95
151
|
* Show the "toggle markers visibility" item in the FAB radial menu.
|
|
96
152
|
* Defaults to `true` (current behavior). Set to `false` to hide that
|
|
@@ -109,7 +165,7 @@ export interface SitepingBaseConfig {
|
|
|
109
165
|
accentColor?: string | undefined;
|
|
110
166
|
/**
|
|
111
167
|
* Render the widget even when it would normally be skipped — this bypasses
|
|
112
|
-
* BOTH the production-environment guard AND the
|
|
168
|
+
* BOTH the production-environment guard AND the `minViewportWidth` guard.
|
|
113
169
|
* It does NOT bypass the SSR guard: without `window`/`document` the widget
|
|
114
170
|
* never renders and `onSkip("ssr")` fires instead.
|
|
115
171
|
* Defaults to false. Use it for dedicated review tools, staging environments,
|
|
@@ -118,18 +174,20 @@ export interface SitepingBaseConfig {
|
|
|
118
174
|
forceShow?: boolean | undefined;
|
|
119
175
|
/**
|
|
120
176
|
* Minimum viewport width (px) at or above which the widget renders. Below it,
|
|
121
|
-
* the widget is skipped and `onSkip("mobile")` fires. Defaults to `
|
|
177
|
+
* the widget is skipped and `onSkip("mobile")` fires. Defaults to `0`: the
|
|
178
|
+
* widget renders at every width, and phones get a compact layout (bottom
|
|
179
|
+
* sheets, touch-sized controls).
|
|
122
180
|
*
|
|
123
|
-
* Set
|
|
124
|
-
* to bypass the viewport check entirely.
|
|
181
|
+
* Set it (e.g. `768`) to keep the widget off small screens, or use
|
|
182
|
+
* `forceShow` to bypass the viewport check entirely.
|
|
125
183
|
*/
|
|
126
184
|
minViewportWidth?: number | undefined;
|
|
127
185
|
/** Enable debug logging of lifecycle events — defaults to false */
|
|
128
186
|
debug?: boolean | undefined;
|
|
129
187
|
/** Color theme — defaults to 'light' */
|
|
130
|
-
theme?:
|
|
131
|
-
/** UI locale — defaults to 'en'. Built-in: en, fr, de, es, it, pt (Brazilian), ru. Any other string falls back to English. */
|
|
132
|
-
locale?:
|
|
188
|
+
theme?: BeezpingTheme | undefined;
|
|
189
|
+
/** UI locale — defaults to 'en'. Built-in: en, fr, de, es, it, pt (Brazilian), ru, ja. Any other string falls back to English. */
|
|
190
|
+
locale?: BeezpingLocale | undefined;
|
|
133
191
|
/**
|
|
134
192
|
* Returns the current page scope for annotations and panel filtering.
|
|
135
193
|
* Called on initial markers load and on `instance.refresh()`.
|
|
@@ -161,7 +219,7 @@ export interface SitepingBaseConfig {
|
|
|
161
219
|
* `html2canvas-pro` ships as a regular dependency of `@beezping/widget` so the
|
|
162
220
|
* dynamic import always resolves; you don't need to install anything extra.
|
|
163
221
|
*
|
|
164
|
-
* **Masking sensitive elements:** add `data-
|
|
222
|
+
* **Masking sensitive elements:** add `data-beezping-ignore="true"` to any
|
|
165
223
|
* element you do NOT want captured (password fields, credit-card forms,
|
|
166
224
|
* API tokens shown in the UI, etc.). The capture predicate skips matching
|
|
167
225
|
* elements *and their descendants*. Do this BEFORE turning on screenshots
|
|
@@ -179,18 +237,21 @@ export interface SitepingBaseConfig {
|
|
|
179
237
|
*
|
|
180
238
|
* Keyboard-triggered context menus (≣ Menu key, Shift+F10) always get the
|
|
181
239
|
* native menu; only mouse right-click and touch/pen long-press open the
|
|
182
|
-
* composer
|
|
240
|
+
* composer — a long-press only where the browser fires `contextmenu` for
|
|
241
|
+
* it, which iOS and iPadOS never do (see the note below).
|
|
183
242
|
*
|
|
184
243
|
* **Modifier-key escape hatch:** holding Shift, Ctrl, Alt, or Meta while
|
|
185
244
|
* right-clicking always falls through to the native context menu, giving
|
|
186
245
|
* users (and devtools) an escape hatch regardless of this setting.
|
|
187
246
|
*
|
|
188
|
-
* Right-clicks on
|
|
247
|
+
* Right-clicks on Beezping's own UI (FAB, panel, markers, popup) are
|
|
189
248
|
* ignored — the native menu is shown as expected.
|
|
190
249
|
*
|
|
191
|
-
* Note: on Android, `contextmenu` fires on long-press
|
|
192
|
-
*
|
|
193
|
-
*
|
|
250
|
+
* Note: on Android, `contextmenu` fires on long-press — touch users open the
|
|
251
|
+
* composer by long-pressing, on phones too since the widget renders at every
|
|
252
|
+
* width by default (see `minViewportWidth`). On iPhone and iPad a long-press
|
|
253
|
+
* never fires `contextmenu` (WebKit bug 213953): users there open annotate
|
|
254
|
+
* mode from the floating button and tap the element.
|
|
194
255
|
*/
|
|
195
256
|
enableRightClickComment?: boolean | undefined;
|
|
196
257
|
/**
|
|
@@ -203,16 +264,19 @@ export interface SitepingBaseConfig {
|
|
|
203
264
|
*
|
|
204
265
|
* - `true` — capture with defaults (50 console / 20 network entries).
|
|
205
266
|
* - `false` (default) — no capture, no monkey-patching.
|
|
206
|
-
* - object — per-channel toggles +
|
|
267
|
+
* - object — per-channel toggles + smaller buffer sizes (values above the
|
|
268
|
+
* 50 / 20 server caps are clamped so submissions never fail validation).
|
|
207
269
|
*
|
|
208
270
|
* **Privacy considerations:** console messages may contain anything the
|
|
209
271
|
* host page logs, including user data. Failed network requests record the
|
|
210
|
-
* URL
|
|
211
|
-
*
|
|
272
|
+
* URL without its credentials, query string or hash, and never the
|
|
273
|
+
* response body.
|
|
274
|
+
* Inform end users before enabling in environments where they might log
|
|
275
|
+
* sensitive values.
|
|
212
276
|
*/
|
|
213
277
|
captureDiagnostics?: boolean | DiagnosticsCaptureOptions | undefined;
|
|
214
|
-
/** Called when the widget is skipped (production mode,
|
|
215
|
-
onSkip?: (reason:
|
|
278
|
+
/** Called when the widget is skipped (production mode, viewport under `minViewportWidth`, SSR — no DOM) */
|
|
279
|
+
onSkip?: (reason: BeezpingSkipReason) => void;
|
|
216
280
|
/**
|
|
217
281
|
* Auto-focus a specific annotation when its ID appears in the URL query
|
|
218
282
|
* string. Lets hosts deeplink directly into a feedback from external
|
|
@@ -226,7 +290,7 @@ export interface SitepingBaseConfig {
|
|
|
226
290
|
*
|
|
227
291
|
* - `false` / `undefined` (default): no URL parsing. Existing behavior
|
|
228
292
|
* unchanged, no host URL inspection.
|
|
229
|
-
* - `true`: enabled with default query parameter name `
|
|
293
|
+
* - `true`: enabled with default query parameter name `beezping`.
|
|
230
294
|
* - object: enabled with a custom parameter name. Use this to avoid
|
|
231
295
|
* clashes with host-app query keys.
|
|
232
296
|
*
|
|
@@ -236,7 +300,7 @@ export interface SitepingBaseConfig {
|
|
|
236
300
|
* Hosts that need re-focus on route change can call
|
|
237
301
|
* `instance.focusFeedback(id)` explicitly.
|
|
238
302
|
*/
|
|
239
|
-
deepLink?: boolean |
|
|
303
|
+
deepLink?: boolean | BeezpingDeepLinkOptions | undefined;
|
|
240
304
|
/**
|
|
241
305
|
* Automatically re-fetch feedbacks when the page changes during client-side
|
|
242
306
|
* (SPA) navigation. Enabled by default.
|
|
@@ -275,26 +339,51 @@ export interface SitepingBaseConfig {
|
|
|
275
339
|
* read at widget init time, not on every render. Hosts that need live
|
|
276
340
|
* identity updates after sign-in/sign-out should currently remount the
|
|
277
341
|
* widget (e.g. via a React `key` on the wrapping component). See
|
|
278
|
-
* https://github.com/
|
|
342
|
+
* https://github.com/guidomodarelli/beezping/issues/85 for tracking a
|
|
279
343
|
* future enhancement that propagates identity updates without a remount.
|
|
280
344
|
*/
|
|
281
|
-
identity?:
|
|
345
|
+
identity?: BeezpingIdentity | undefined;
|
|
346
|
+
/**
|
|
347
|
+
* Host-defined actions rendered in the feedback detail view, below the
|
|
348
|
+
* built-in Resolve and Delete buttons. Read once when the panel loads:
|
|
349
|
+
* entries without a non-empty `id` and `label`, without exactly one of
|
|
350
|
+
* `onAction` / `href`, with an unsafe static `href`, or reusing an earlier
|
|
351
|
+
* `id` are skipped with a console warning. See {@link BeezpingPanelAction}.
|
|
352
|
+
*/
|
|
353
|
+
panelActions?: readonly BeezpingPanelAction[] | undefined;
|
|
354
|
+
/**
|
|
355
|
+
* Reviewer mode: hide the actions that triage feedback — resolve, reopen,
|
|
356
|
+
* delete, the bulk actions, "Delete all" — and keep creating, browsing
|
|
357
|
+
* and replying. Defaults to `false`. The server's `permissions` hide
|
|
358
|
+
* what it would refuse on top of it. It only hides: the server decides
|
|
359
|
+
* what it accepts. Read once when the panel loads.
|
|
360
|
+
*/
|
|
361
|
+
readOnly?: boolean | undefined;
|
|
282
362
|
/** Called when the feedback panel is opened. */
|
|
283
363
|
onOpen?: (() => void) | undefined;
|
|
284
364
|
/** Called when the feedback panel is closed. */
|
|
285
365
|
onClose?: (() => void) | undefined;
|
|
286
366
|
/** Called after a feedback is successfully submitted. */
|
|
287
367
|
onFeedbackSent?: ((feedback: FeedbackResponse) => void) | undefined;
|
|
368
|
+
/** Called after a reply is posted from the panel's discussion thread. */
|
|
369
|
+
onCommentAdded?: ((comment: CommentResponse) => void) | undefined;
|
|
288
370
|
/**
|
|
289
371
|
* Called when a feedback API call fails.
|
|
290
372
|
*
|
|
291
|
-
* The widget always emits a `
|
|
292
|
-
* `
|
|
373
|
+
* The widget always emits a `BeezpingError` (or a subclass:
|
|
374
|
+
* `BeezpingNetworkError`, `BeezpingValidationError`, `BeezpingAuthError`)
|
|
293
375
|
* for HTTP-mode failures — host apps can `instanceof` to drive retry
|
|
294
376
|
* logic, or read `error.code` (`"NETWORK" | "VALIDATION" | "AUTH" |
|
|
295
|
-
* "SERVER"`) and `error.retryable
|
|
296
|
-
*
|
|
297
|
-
*
|
|
377
|
+
* "SERVER"`) and `error.retryable` — and an `AUTH` error's `status`
|
|
378
|
+
* (`401` for missing or dead credentials, `403` for a refusal). The type
|
|
379
|
+
* is widened to `Error` so direct-store callers can still surface raw
|
|
380
|
+
* errors without breaking the contract.
|
|
381
|
+
*
|
|
382
|
+
* Also receives whatever a `panelActions` callback throws or rejects with
|
|
383
|
+
* (non-`Error` values are wrapped). Those host failures are not API
|
|
384
|
+
* failures, so they are not emitted on the public `feedback:error` event.
|
|
385
|
+
* The widget has no UI for them, so they are also always logged with
|
|
386
|
+
* `console.error`, whether or not `onError` is set.
|
|
298
387
|
*/
|
|
299
388
|
onError?: ((error: Error) => void) | undefined;
|
|
300
389
|
/** Called when the user starts drawing an annotation. */
|
|
@@ -306,8 +395,8 @@ export interface SitepingBaseConfig {
|
|
|
306
395
|
* HTTP mode — the widget talks to a server endpoint backed by a store
|
|
307
396
|
* adapter (e.g. `@beezping/adapter-prisma` request handlers).
|
|
308
397
|
*/
|
|
309
|
-
export interface
|
|
310
|
-
/** HTTP endpoint that receives feedbacks (e.g. '/api/
|
|
398
|
+
export interface BeezpingHttpConfig extends BeezpingBaseConfig {
|
|
399
|
+
/** HTTP endpoint that receives feedbacks (e.g. '/api/beezping'). */
|
|
311
400
|
endpoint: string;
|
|
312
401
|
/**
|
|
313
402
|
* Convenience auth for HTTP mode — sent as `Authorization: Bearer <apiKey>`
|
|
@@ -323,60 +412,44 @@ export interface SitepingHttpConfig extends SitepingBaseConfig {
|
|
|
323
412
|
/**
|
|
324
413
|
* Extra headers for every HTTP-mode request — a static map, or a factory
|
|
325
414
|
* (sync or async) called once per request (e.g. to fetch a fresh session
|
|
326
|
-
* token). Merged over the widget's generated headers,
|
|
327
|
-
* `Authorization` entry overrides `apiKey`. A
|
|
328
|
-
* fails the request like a
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
* Cookie policy for every HTTP-mode request (submit, list, update, delete
|
|
333
|
-
* and the offline retry-queue replay). Defaults to `"same-origin"` — the
|
|
334
|
-
* browser default, so existing setups are unchanged.
|
|
335
|
-
*
|
|
336
|
-
* Set `"include"` when `endpoint` lives on **another origin** and the
|
|
337
|
-
* server authenticates with a session cookie (e.g. a custom
|
|
338
|
-
* `access.authenticate` in `@beezping/server`): without it the browser
|
|
339
|
-
* never attaches the cookie and every request is rejected as
|
|
340
|
-
* unauthenticated. The server must allow the page's origin explicitly with
|
|
341
|
-
* credentialed CORS (`allowedOrigins`) — a wildcard origin never works
|
|
342
|
-
* with cookies. Only opt in for origins you trust: cookie-authenticated
|
|
343
|
-
* cross-origin requests rely on the server's CSRF defenses (strict origin
|
|
344
|
-
* allowlist, `SameSite` cookies).
|
|
345
|
-
*
|
|
346
|
-
* An unknown value (untyped script-tag config) is rejected at init: the
|
|
347
|
-
* widget logs an error and does not load.
|
|
348
|
-
*/
|
|
349
|
-
credentials?: SitepingRequestCredentials | undefined;
|
|
415
|
+
* token). Merged over the widget's generated headers, case-insensitively,
|
|
416
|
+
* so an explicit `Authorization` entry overrides `apiKey`. A factory that
|
|
417
|
+
* throws, rejects, or does not settle within 10 s fails the request like a
|
|
418
|
+
* network error.
|
|
419
|
+
*/
|
|
420
|
+
headers?: BeezpingHeadersOption | undefined;
|
|
350
421
|
/** Not available in HTTP mode — use either `endpoint` or `store`, never both. */
|
|
351
422
|
store?: never;
|
|
352
423
|
}
|
|
353
424
|
/**
|
|
354
|
-
* Store mode — the widget talks to a `
|
|
425
|
+
* Store mode — the widget talks to a `BeezpingStore` directly in the
|
|
355
426
|
* browser, no server needed (demos, prototypes, localStorage persistence).
|
|
356
427
|
*/
|
|
357
|
-
export interface
|
|
358
|
-
/**
|
|
359
|
-
|
|
428
|
+
export interface BeezpingStoreConfig extends BeezpingBaseConfig {
|
|
429
|
+
/**
|
|
430
|
+
* Direct store for client-side mode. Bypasses HTTP entirely. A send stops
|
|
431
|
+
* waiting on `createFeedback` after 30 s (the call itself cannot be
|
|
432
|
+
* cancelled), so a network-backed store should bound its own calls.
|
|
433
|
+
*/
|
|
434
|
+
store: BeezpingStore;
|
|
360
435
|
/** Not available in store mode — use either `endpoint` or `store`, never both. */
|
|
361
436
|
endpoint?: never;
|
|
362
437
|
/** HTTP-mode only — meaningless without an `endpoint`. */
|
|
363
438
|
apiKey?: never;
|
|
364
439
|
/** HTTP-mode only — meaningless without an `endpoint`. */
|
|
365
440
|
headers?: never;
|
|
366
|
-
/** HTTP-mode only — meaningless without an `endpoint`. */
|
|
367
|
-
credentials?: never;
|
|
368
441
|
}
|
|
369
442
|
/**
|
|
370
|
-
* Configuration options for the
|
|
443
|
+
* Configuration options for the Beezping widget.
|
|
371
444
|
*
|
|
372
445
|
* A discriminated union over the two transport modes: pass `endpoint`
|
|
373
|
-
* (HTTP mode, optionally with `apiKey`/`headers
|
|
446
|
+
* (HTTP mode, optionally with `apiKey`/`headers`) **or** `store` (direct
|
|
374
447
|
* client-side mode) — never both, never neither. Invalid combinations are
|
|
375
448
|
* compile errors instead of runtime warnings.
|
|
376
449
|
*/
|
|
377
|
-
export type
|
|
378
|
-
/** Instance returned by
|
|
379
|
-
export interface
|
|
450
|
+
export type BeezpingConfig = BeezpingHttpConfig | BeezpingStoreConfig;
|
|
451
|
+
/** Instance returned by initBeezping() with lifecycle methods. */
|
|
452
|
+
export interface BeezpingInstance {
|
|
380
453
|
/** Remove the widget from the DOM and clean up all listeners. */
|
|
381
454
|
destroy: () => void;
|
|
382
455
|
/** Open the panel programmatically */
|
|
@@ -397,21 +470,23 @@ export interface SitepingInstance {
|
|
|
397
470
|
*/
|
|
398
471
|
focusFeedback: (feedbackId: string) => boolean;
|
|
399
472
|
/** Subscribe to a public widget event */
|
|
400
|
-
on: <K extends keyof
|
|
473
|
+
on: <K extends keyof BeezpingPublicEvents>(event: K, listener: BeezpingPublicEventListener<K>) => BeezpingUnsubscribe;
|
|
401
474
|
/** Unsubscribe from a public widget event */
|
|
402
|
-
off: <K extends keyof
|
|
403
|
-
}
|
|
404
|
-
/** Listener signature for a single `
|
|
405
|
-
export type
|
|
406
|
-
/** Disposer returned by `
|
|
407
|
-
export type
|
|
408
|
-
/** Events exposed to consumers via
|
|
409
|
-
export interface
|
|
475
|
+
off: <K extends keyof BeezpingPublicEvents>(event: K, listener: BeezpingPublicEventListener<K>) => void;
|
|
476
|
+
}
|
|
477
|
+
/** Listener signature for a single `BeezpingPublicEvents` key. */
|
|
478
|
+
export type BeezpingPublicEventListener<K extends keyof BeezpingPublicEvents> = (...args: BeezpingPublicEvents[K]) => void;
|
|
479
|
+
/** Disposer returned by `BeezpingInstance.on` — call once to detach the listener. */
|
|
480
|
+
export type BeezpingUnsubscribe = () => void;
|
|
481
|
+
/** Events exposed to consumers via BeezpingInstance.on / .off */
|
|
482
|
+
export interface BeezpingPublicEvents {
|
|
410
483
|
"feedback:sent": [FeedbackResponse];
|
|
411
484
|
"feedback:deleted": [FeedbackResponse["id"]];
|
|
485
|
+
/** A reply was posted from the panel's discussion thread. */
|
|
486
|
+
"comment:added": [CommentResponse];
|
|
412
487
|
/**
|
|
413
488
|
* A feedback API call failed. Same payload contract as
|
|
414
|
-
* `
|
|
489
|
+
* `BeezpingConfig.onError` — a `BeezpingError` subclass in HTTP mode,
|
|
415
490
|
* possibly a raw `Error` in store mode.
|
|
416
491
|
*/
|
|
417
492
|
"feedback:error": [Error];
|
|
@@ -444,7 +519,7 @@ export type OpenFeedbackStatus = (typeof OPEN_FEEDBACK_STATUSES)[number];
|
|
|
444
519
|
/** Whether a status is terminal (`resolved` or `wont_fix`). Narrows the status type. */
|
|
445
520
|
export declare function isClosedStatus(status: FeedbackStatus): status is ClosedFeedbackStatus;
|
|
446
521
|
/**
|
|
447
|
-
* Page scope returned by `
|
|
522
|
+
* Page scope returned by `BeezpingConfig.getPageScope()`.
|
|
448
523
|
*
|
|
449
524
|
* - `url`: concrete page identifier — usually `window.location.pathname`,
|
|
450
525
|
* used as the strict scope for marker rendering.
|
|
@@ -495,7 +570,7 @@ export interface FeedbackCreateInput {
|
|
|
495
570
|
screenshotRegion?: ScreenshotRegion | null | undefined;
|
|
496
571
|
/**
|
|
497
572
|
* Optional console + failed-network snapshot captured by the widget when
|
|
498
|
-
* `
|
|
573
|
+
* `BeezpingConfig.captureDiagnostics` is enabled. Stored as JSON on
|
|
499
574
|
* `FeedbackRecord.diagnostics` so reviewers can replay the context.
|
|
500
575
|
*/
|
|
501
576
|
diagnostics?: DiagnosticsSnapshot | null | undefined;
|
|
@@ -543,6 +618,11 @@ export interface FeedbackQuery {
|
|
|
543
618
|
statuses?: readonly FeedbackStatus[] | undefined;
|
|
544
619
|
search?: string | undefined;
|
|
545
620
|
page?: number | undefined;
|
|
621
|
+
/**
|
|
622
|
+
* Page size. Defaults to `DEFAULT_PAGE_LIMIT` (50) and is capped at
|
|
623
|
+
* `MAX_PAGE_LIMIT` (100) — `clampPagination` implements both, and the
|
|
624
|
+
* conformance suite checks them.
|
|
625
|
+
*/
|
|
546
626
|
limit?: number | undefined;
|
|
547
627
|
/**
|
|
548
628
|
* Filter to feedbacks created on this exact URL (path). Used by the panel's
|
|
@@ -601,6 +681,13 @@ export interface FeedbackRecord {
|
|
|
601
681
|
createdAt: Date;
|
|
602
682
|
updatedAt: Date;
|
|
603
683
|
annotations: AnnotationRecord[];
|
|
684
|
+
/**
|
|
685
|
+
* Discussion thread, oldest first. A store that implements
|
|
686
|
+
* `BeezpingStore.addComment` returns it on every record; a store without
|
|
687
|
+
* comments may leave it out, which reads as an empty thread (HTTP handlers
|
|
688
|
+
* send `[]`).
|
|
689
|
+
*/
|
|
690
|
+
comments?: CommentRecord[] | undefined;
|
|
604
691
|
/**
|
|
605
692
|
* URL the widget renders as `<img src>`. Either an `https://...` from a
|
|
606
693
|
* configured `ScreenshotStorage`, or a `data:image/jpeg;base64,...` URL
|
|
@@ -648,6 +735,66 @@ export interface AnnotationRecord {
|
|
|
648
735
|
devicePixelRatio: number;
|
|
649
736
|
createdAt: Date;
|
|
650
737
|
}
|
|
738
|
+
/**
|
|
739
|
+
* Who wrote a comment: `client` — the reviewer on the site (the widget) —
|
|
740
|
+
* or `team` — the project side (the dashboard). HTTP handlers stamp
|
|
741
|
+
* `client` unless the server's access policy vouches for the caller, so a
|
|
742
|
+
* visitor cannot pose as the team.
|
|
743
|
+
*/
|
|
744
|
+
export declare const COMMENT_AUTHOR_ROLES: readonly ["client", "team"];
|
|
745
|
+
export type CommentAuthorRole = (typeof COMMENT_AUTHOR_ROLES)[number];
|
|
746
|
+
/** Longest comment `body` the HTTP API accepts — the cap of a feedback `message`. */
|
|
747
|
+
export declare const COMMENT_BODY_MAX_LENGTH = 5000;
|
|
748
|
+
/**
|
|
749
|
+
* Most `client` comments one thread holds. List responses embed whole
|
|
750
|
+
* threads, which are not paginated, so this bounds what one feedback weighs
|
|
751
|
+
* however much a public endpoint is spammed. `team` comments — a role only
|
|
752
|
+
* the access policy grants — neither count nor meet it: a thread spammed
|
|
753
|
+
* full still takes the team's answer. Stores enforce it with
|
|
754
|
+
* `StoreLimitError`; a store without an atomic primitive may overshoot it by
|
|
755
|
+
* the posts that race the last free slot.
|
|
756
|
+
*/
|
|
757
|
+
export declare const MAX_COMMENTS_PER_FEEDBACK = 100;
|
|
758
|
+
/** A persisted comment returned by the store. */
|
|
759
|
+
export interface CommentRecord {
|
|
760
|
+
id: string;
|
|
761
|
+
/** The feedback whose thread holds this comment. */
|
|
762
|
+
feedbackId: string;
|
|
763
|
+
body: string;
|
|
764
|
+
authorName: string;
|
|
765
|
+
/**
|
|
766
|
+
* Author email, or `""` when the author has none on file (a dashboard
|
|
767
|
+
* user). HTTP handlers redact it exactly like `FeedbackRecord.authorEmail`.
|
|
768
|
+
*/
|
|
769
|
+
authorEmail: string;
|
|
770
|
+
authorRole: CommentAuthorRole;
|
|
771
|
+
/** Client-generated id — `addComment` is idempotent on it, so a retried post never duplicates a reply. */
|
|
772
|
+
clientId: string;
|
|
773
|
+
createdAt: Date;
|
|
774
|
+
}
|
|
775
|
+
/** Input of `BeezpingStore.addComment`. */
|
|
776
|
+
export interface CommentCreateInput {
|
|
777
|
+
body: string;
|
|
778
|
+
authorName: string;
|
|
779
|
+
authorEmail: string;
|
|
780
|
+
authorRole: CommentAuthorRole;
|
|
781
|
+
clientId: string;
|
|
782
|
+
}
|
|
783
|
+
/**
|
|
784
|
+
* Body of a comment `POST`. `feedbackId` is what tells it apart from a
|
|
785
|
+
* feedback submission on the same endpoint; `projectName` scopes the write
|
|
786
|
+
* to that project's feedbacks.
|
|
787
|
+
*/
|
|
788
|
+
export interface CommentPayload extends CommentCreateInput {
|
|
789
|
+
projectName: string;
|
|
790
|
+
feedbackId: string;
|
|
791
|
+
}
|
|
792
|
+
/** Body of a comment `DELETE` — `commentId` is what tells it apart from a feedback delete. */
|
|
793
|
+
export interface CommentDeletePayload {
|
|
794
|
+
projectName: string;
|
|
795
|
+
feedbackId: string;
|
|
796
|
+
commentId: string;
|
|
797
|
+
}
|
|
651
798
|
/**
|
|
652
799
|
* Thrown when a record is not found during update or delete.
|
|
653
800
|
*
|
|
@@ -677,24 +824,41 @@ export declare class StorePersistenceError extends Error {
|
|
|
677
824
|
readonly code: "STORE_PERSISTENCE";
|
|
678
825
|
constructor(message?: string, options?: ErrorOptions);
|
|
679
826
|
}
|
|
827
|
+
/**
|
|
828
|
+
* Thrown when a write would break a bound of the store contract — a
|
|
829
|
+
* `client` comment on a thread already holding `MAX_COMMENTS_PER_FEEDBACK`
|
|
830
|
+
* of them. Handlers translate this to HTTP 409.
|
|
831
|
+
*/
|
|
832
|
+
export declare class StoreLimitError extends Error {
|
|
833
|
+
readonly code: "STORE_LIMIT";
|
|
834
|
+
constructor(message?: string, options?: ErrorOptions);
|
|
835
|
+
}
|
|
836
|
+
/**
|
|
837
|
+
* Thrown when a value is longer than the store can hold, though the HTTP
|
|
838
|
+
* validation accepts it — on MySQL, Prisma maps a plain `String` to
|
|
839
|
+
* `VARCHAR(191)`. Handlers translate this to HTTP 422: the submission can
|
|
840
|
+
* never be stored as it is, so a client must not retry it.
|
|
841
|
+
*/
|
|
842
|
+
export declare class StoreValueTooLongError extends Error {
|
|
843
|
+
readonly code: "STORE_VALUE_TOO_LONG";
|
|
844
|
+
constructor(message?: string, options?: ErrorOptions);
|
|
845
|
+
}
|
|
680
846
|
/** Shape of any ORM error that carries a Prisma-style `code` field. */
|
|
681
847
|
type CodedError<C extends string = string> = {
|
|
682
848
|
code: C;
|
|
683
849
|
};
|
|
684
850
|
/**
|
|
685
851
|
* Type guard — works for `StoreNotFoundError` and ORM-specific equivalents
|
|
686
|
-
* (e.g. Prisma P2025). Matches the stable `
|
|
687
|
-
*
|
|
688
|
-
* `noExternal`), so an adapter's instance fails `instanceof` against the
|
|
689
|
-
* server's class identity.
|
|
852
|
+
* (e.g. Prisma P2025). Matches on the stable `code` too, for the same
|
|
853
|
+
* cross-bundle reason as {@link isStorePersistence}.
|
|
690
854
|
*/
|
|
691
|
-
export declare function isStoreNotFound(error: unknown): error is StoreNotFoundError | CodedError<"STORE_NOT_FOUND"
|
|
855
|
+
export declare function isStoreNotFound(error: unknown): error is StoreNotFoundError | CodedError<"STORE_NOT_FOUND" | "P2025">;
|
|
692
856
|
/**
|
|
693
857
|
* Type guard — works for `StoreDuplicateError` and ORM-specific equivalents
|
|
694
|
-
* (e.g. Prisma P2002). Matches the stable `
|
|
695
|
-
*
|
|
858
|
+
* (e.g. Prisma P2002). Matches on the stable `code` too, for the same
|
|
859
|
+
* cross-bundle reason as {@link isStorePersistence}.
|
|
696
860
|
*/
|
|
697
|
-
export declare function isStoreDuplicate(error: unknown): error is StoreDuplicateError | CodedError<"STORE_DUPLICATE"
|
|
861
|
+
export declare function isStoreDuplicate(error: unknown): error is StoreDuplicateError | CodedError<"STORE_DUPLICATE" | "P2002">;
|
|
698
862
|
/**
|
|
699
863
|
* Type guard for `StorePersistenceError`. Matches on the stable `code` field
|
|
700
864
|
* in addition to `instanceof`: every consumer package bundles its own copy of
|
|
@@ -702,10 +866,14 @@ export declare function isStoreDuplicate(error: unknown): error is StoreDuplicat
|
|
|
702
866
|
* `instanceof` check against another package's class identity.
|
|
703
867
|
*/
|
|
704
868
|
export declare function isStorePersistence(error: unknown): error is StorePersistenceError | CodedError<"STORE_PERSISTENCE">;
|
|
869
|
+
/** Type guard for `StoreLimitError`, matching on `code` for the same cross-bundle reason as {@link isStorePersistence}. */
|
|
870
|
+
export declare function isStoreLimit(error: unknown): error is StoreLimitError | CodedError<"STORE_LIMIT">;
|
|
871
|
+
/** Type guard for `StoreValueTooLongError`, matching on `code` for the same cross-bundle reason as {@link isStorePersistence}. */
|
|
872
|
+
export declare function isStoreValueTooLong(error: unknown): error is StoreValueTooLongError | CodedError<"STORE_VALUE_TOO_LONG">;
|
|
705
873
|
/** Flatten a widget `AnnotationPayload` (nested anchor + rect) into a flat `AnnotationCreateInput`. */
|
|
706
874
|
export declare function flattenAnnotation(ann: AnnotationPayload): AnnotationCreateInput;
|
|
707
875
|
/**
|
|
708
|
-
* Outcome of `
|
|
876
|
+
* Outcome of `BeezpingStore.createFeedbackIfAbsent` — the record plus whether
|
|
709
877
|
* this very call inserted it.
|
|
710
878
|
*/
|
|
711
879
|
export interface FeedbackCreateOutcome {
|
|
@@ -717,17 +885,17 @@ export interface FeedbackCreateOutcome {
|
|
|
717
885
|
*/
|
|
718
886
|
created: boolean;
|
|
719
887
|
}
|
|
720
|
-
/** Paginated result returned by `
|
|
888
|
+
/** Paginated result returned by `BeezpingStore.getFeedbacks`. */
|
|
721
889
|
export interface FeedbackPage {
|
|
722
890
|
feedbacks: FeedbackRecord[];
|
|
723
891
|
total: number;
|
|
724
892
|
}
|
|
725
893
|
/**
|
|
726
|
-
* Abstract storage interface for
|
|
894
|
+
* Abstract storage interface for Beezping.
|
|
727
895
|
*
|
|
728
896
|
* Any adapter (Prisma, Drizzle, raw SQL, localStorage, etc.) implements this
|
|
729
897
|
* interface. The HTTP handler and widget `StoreClient` operate against
|
|
730
|
-
* `
|
|
898
|
+
* `BeezpingStore`, decoupled from the storage backend.
|
|
731
899
|
*
|
|
732
900
|
* ## Error contract
|
|
733
901
|
*
|
|
@@ -744,7 +912,7 @@ export interface FeedbackPage {
|
|
|
744
912
|
* a phantom success. Detect it with `isStorePersistence`.
|
|
745
913
|
* - Other methods should not throw on empty results — return empty arrays or `null`.
|
|
746
914
|
*/
|
|
747
|
-
export interface
|
|
915
|
+
export interface BeezpingStore {
|
|
748
916
|
/** Create a feedback with its annotations. Idempotent on `clientId` — return existing record on duplicate, or throw `StoreDuplicateError`. Throws `StorePersistenceError` when the write cannot be persisted. */
|
|
749
917
|
createFeedback(data: FeedbackCreateInput): Promise<FeedbackRecord>;
|
|
750
918
|
/** Paginated query with optional filters. Returns empty array (not error) when no results. */
|
|
@@ -762,10 +930,8 @@ export interface SitepingStore {
|
|
|
762
930
|
* `projectName`, `false` otherwise (including when it does not exist).
|
|
763
931
|
*
|
|
764
932
|
* HTTP handlers use this to reject cross-project PATCH/DELETE requests.
|
|
765
|
-
* Implement it whenever your store serves multiple projects
|
|
766
|
-
* handlers rely on `id` alone
|
|
767
|
-
* with a custom `access.authorize` (which may scope callers to projects)
|
|
768
|
-
* over a store that lacks it.
|
|
933
|
+
* Implement it whenever your store serves multiple projects; when absent,
|
|
934
|
+
* handlers skip the ownership check and rely on `id` alone.
|
|
769
935
|
*/
|
|
770
936
|
verifyProjectOwnership?(id: string, projectName: string): Promise<boolean>;
|
|
771
937
|
/**
|
|
@@ -780,12 +946,39 @@ export interface SitepingStore {
|
|
|
780
946
|
* transaction, compare-and-set).
|
|
781
947
|
*
|
|
782
948
|
* HTTP handlers prefer it over `createFeedback` to fire creation side
|
|
783
|
-
* effects (webhooks
|
|
784
|
-
*
|
|
949
|
+
* effects (webhooks) exactly once when concurrent requests race on the
|
|
950
|
+
* same `clientId`. Stores whose `createFeedback` throws
|
|
785
951
|
* `StoreDuplicateError` on a duplicate already give that signal and may
|
|
786
952
|
* leave it out.
|
|
787
953
|
*/
|
|
788
954
|
createFeedbackIfAbsent?(data: FeedbackCreateInput): Promise<FeedbackCreateOutcome>;
|
|
955
|
+
/**
|
|
956
|
+
* Optional — append a comment to the thread of feedback `feedbackId` and
|
|
957
|
+
* return it. Idempotent on `data.clientId`: when a comment with that
|
|
958
|
+
* `clientId` exists, on any thread, return it unchanged (HTTP handlers
|
|
959
|
+
* refuse a replay aimed at another thread).
|
|
960
|
+
*
|
|
961
|
+
* Throws `StoreNotFoundError` when the feedback does not exist,
|
|
962
|
+
* `StoreLimitError` when a `client` comment meets a thread already holding
|
|
963
|
+
* `MAX_COMMENTS_PER_FEEDBACK` of them (a `team` comment is never refused
|
|
964
|
+
* for it), `StorePersistenceError` when the
|
|
965
|
+
* write cannot be persisted. A comment is not a change of the feedback
|
|
966
|
+
* itself: its `updatedAt` stays as it was.
|
|
967
|
+
*
|
|
968
|
+
* A store that implements it returns every feedback's thread on
|
|
969
|
+
* `FeedbackRecord.comments`, oldest first, and deletes a thread with its
|
|
970
|
+
* feedback. A store without it (and `deleteComment`) has no threads:
|
|
971
|
+
* HTTP handlers serve empty threads and answer comment writes with 501.
|
|
972
|
+
*/
|
|
973
|
+
addComment?(feedbackId: string, data: CommentCreateInput): Promise<CommentRecord>;
|
|
974
|
+
/**
|
|
975
|
+
* Optional — delete comment `commentId` from the thread of `feedbackId`.
|
|
976
|
+
* Scoped to that thread, which the caller was authorized for: throws
|
|
977
|
+
* `StoreNotFoundError` when the feedback does not exist or the comment is
|
|
978
|
+
* not on its thread, `StorePersistenceError` when the write cannot be
|
|
979
|
+
* persisted.
|
|
980
|
+
*/
|
|
981
|
+
deleteComment?(feedbackId: string, commentId: string): Promise<void>;
|
|
789
982
|
}
|
|
790
983
|
/** Payload sent from the widget to the server when submitting feedback. */
|
|
791
984
|
export interface FeedbackPayload {
|
|
@@ -795,7 +988,7 @@ export interface FeedbackPayload {
|
|
|
795
988
|
url: string;
|
|
796
989
|
/**
|
|
797
990
|
* Parameterized URL template (e.g. `/orders/:orderId`) supplied by
|
|
798
|
-
* `
|
|
991
|
+
* `BeezpingConfig.getPageScope()`. Null when the host did not provide one.
|
|
799
992
|
*/
|
|
800
993
|
urlPattern?: string | null | undefined;
|
|
801
994
|
viewport: string;
|
|
@@ -807,7 +1000,7 @@ export interface FeedbackPayload {
|
|
|
807
1000
|
clientId: string;
|
|
808
1001
|
/**
|
|
809
1002
|
* Base64 JPEG `data:` URL of the annotated area. Captured by the widget
|
|
810
|
-
* when `enableScreenshot: true` is set in `
|
|
1003
|
+
* when `enableScreenshot: true` is set in `BeezpingConfig`. Null when
|
|
811
1004
|
* disabled or when capture failed silently.
|
|
812
1005
|
*/
|
|
813
1006
|
screenshotDataUrl?: string | null | undefined;
|
|
@@ -857,11 +1050,26 @@ export interface DiagnosticsSnapshot {
|
|
|
857
1050
|
console: ConsoleDiagnosticEntry[];
|
|
858
1051
|
network: NetworkDiagnosticEntry[];
|
|
859
1052
|
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Length caps for `AnchorData.elementTag` / `elementId`, shared by the widget
|
|
1055
|
+
* (which bounds what it captures) and the HTTP adapter (which rejects a longer
|
|
1056
|
+
* tag and drops a longer id) so the two can't drift. 191 fits Prisma's default `String` column
|
|
1057
|
+
* on MySQL (`VARCHAR(191)`); real tag names and ids are far shorter.
|
|
1058
|
+
*/
|
|
1059
|
+
export declare const ANCHOR_ELEMENT_TAG_MAX = 191;
|
|
1060
|
+
export declare const ANCHOR_ELEMENT_ID_MAX = 191;
|
|
860
1061
|
/** DOM anchoring data for re-attaching annotations to page elements. */
|
|
861
1062
|
export interface AnchorData {
|
|
862
|
-
/**
|
|
1063
|
+
/**
|
|
1064
|
+
* CSS selector generated by @medv/finder — primary anchor. Inside open
|
|
1065
|
+
* shadow roots: one selector per tree, outermost host first, joined by
|
|
1066
|
+
* `" >>> "` (e.g. `"#pricing >>> .plan-title"`).
|
|
1067
|
+
*/
|
|
863
1068
|
cssSelector: string;
|
|
864
|
-
/**
|
|
1069
|
+
/**
|
|
1070
|
+
* XPath — fallback 1. Inside a shadow root it is relative to that root
|
|
1071
|
+
* (`./…`) and informational only: XPath cannot enter shadow trees.
|
|
1072
|
+
*/
|
|
865
1073
|
xpath: string;
|
|
866
1074
|
/** First ~120 chars of element innerText — empty string if none */
|
|
867
1075
|
textSnippet: string;
|
|
@@ -926,22 +1134,73 @@ export interface AnnotationPayload {
|
|
|
926
1134
|
/**
|
|
927
1135
|
* Feedback record as returned by the API — derived from
|
|
928
1136
|
* {@link FeedbackRecord}: dates are serialized to ISO strings and `clientId`
|
|
929
|
-
* is omitted (server-side dedup concern, never exposed on the wire)
|
|
930
|
-
*
|
|
1137
|
+
* is omitted (server-side dedup concern, never exposed on the wire), on the
|
|
1138
|
+
* record and on each comment of its thread. Adding a field to
|
|
1139
|
+
* `FeedbackRecord` updates this type automatically.
|
|
931
1140
|
*
|
|
932
1141
|
* Note: `authorEmail` may be an empty string — HTTP adapters redact it for
|
|
933
1142
|
* unauthenticated requests; the full value requires a Bearer-authenticated
|
|
934
1143
|
* request.
|
|
935
1144
|
*/
|
|
936
|
-
export type FeedbackResponse = Prettify<Serialized<Omit<FeedbackRecord, "clientId"
|
|
1145
|
+
export type FeedbackResponse = Prettify<Serialized<Omit<FeedbackRecord, "clientId" | "comments">> & {
|
|
1146
|
+
/** The thread, oldest first — always sent by `@beezping/server`, absent from servers that predate comments. */
|
|
1147
|
+
comments?: CommentResponse[] | undefined;
|
|
1148
|
+
/**
|
|
1149
|
+
* What the requester may do with this feedback — always sent by
|
|
1150
|
+
* `@beezping/server`. Absent from servers that predate it, and in store
|
|
1151
|
+
* mode: nothing is refused then.
|
|
1152
|
+
*/
|
|
1153
|
+
permissions?: FeedbackPermissions | undefined;
|
|
1154
|
+
}>;
|
|
1155
|
+
/**
|
|
1156
|
+
* What a requester may do with one feedback, as the server's access policy
|
|
1157
|
+
* decides — so clients hide the actions it would refuse. The server still
|
|
1158
|
+
* enforces every one of them.
|
|
1159
|
+
*/
|
|
1160
|
+
export interface FeedbackPermissions {
|
|
1161
|
+
/** Change its status: resolve, reopen, … */
|
|
1162
|
+
canChangeStatus: boolean;
|
|
1163
|
+
/** Delete it. */
|
|
1164
|
+
canDelete: boolean;
|
|
1165
|
+
/** Reply in its thread. */
|
|
1166
|
+
canComment: boolean;
|
|
1167
|
+
/** Delete replies from its thread. */
|
|
1168
|
+
canDeleteComment: boolean;
|
|
1169
|
+
}
|
|
1170
|
+
/** What a requester may do with a whole project, sent with each list. */
|
|
1171
|
+
export interface FeedbackListPermissions {
|
|
1172
|
+
/** Delete every feedback of the project at once. */
|
|
1173
|
+
canDeleteAll: boolean;
|
|
1174
|
+
}
|
|
937
1175
|
/**
|
|
938
1176
|
* Annotation record as returned by the API — {@link AnnotationRecord} with
|
|
939
1177
|
* `createdAt` serialized to an ISO string.
|
|
940
1178
|
*/
|
|
941
1179
|
export type AnnotationResponse = Prettify<Serialized<AnnotationRecord>>;
|
|
1180
|
+
/**
|
|
1181
|
+
* Comment as returned by the API — {@link CommentRecord} with `createdAt`
|
|
1182
|
+
* serialized and `clientId` omitted, like on `FeedbackResponse`. Its
|
|
1183
|
+
* `authorEmail` is redacted on the same terms as the feedback's.
|
|
1184
|
+
*/
|
|
1185
|
+
export type CommentResponse = Prettify<Serialized<Omit<CommentRecord, "clientId">>>;
|
|
1186
|
+
/** What the store behind an endpoint supports — advertised on every list response. */
|
|
1187
|
+
export interface BeezpingCapabilities {
|
|
1188
|
+
/** Whether comments can be posted: the store implements `addComment`. */
|
|
1189
|
+
comments: boolean;
|
|
1190
|
+
/**
|
|
1191
|
+
* Whether comments can be deleted: the store implements `deleteComment`.
|
|
1192
|
+
* Sent by `@beezping/server`; a client that does not delete (the widget)
|
|
1193
|
+
* leaves it out.
|
|
1194
|
+
*/
|
|
1195
|
+
deleteComments?: boolean | undefined;
|
|
1196
|
+
}
|
|
942
1197
|
/** Paginated `FeedbackResponse` shape returned by the API. */
|
|
943
1198
|
export interface FeedbackResponseList {
|
|
944
1199
|
feedbacks: FeedbackResponse[];
|
|
945
1200
|
total: number;
|
|
1201
|
+
/** Always sent by `@beezping/server` — absent from servers that predate it. */
|
|
1202
|
+
capabilities?: BeezpingCapabilities | undefined;
|
|
1203
|
+
/** Always sent by `@beezping/server` — absent from servers that predate it. */
|
|
1204
|
+
permissions?: FeedbackListPermissions | undefined;
|
|
946
1205
|
}
|
|
947
1206
|
export {};
|