@siteping/widget 0.10.10 → 0.11.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/README.md +5 -4
- package/dist/chunk-CVWZCWBQ.js +9 -0
- package/dist/chunk-CVWZCWBQ.js.map +1 -0
- package/dist/chunk-CX5YE4V3.js +9 -0
- package/dist/chunk-CX5YE4V3.js.map +1 -0
- package/dist/chunk-KCOX2NRI.cjs +9 -0
- package/dist/chunk-KCOX2NRI.cjs.map +1 -0
- package/dist/chunk-QW2L5ARZ.cjs +9 -0
- package/dist/chunk-QW2L5ARZ.cjs.map +1 -0
- package/dist/concurrency.d.cts +14 -0
- package/dist/concurrency.d.ts +14 -0
- package/dist/de-73CTH2E4.cjs +2 -0
- package/dist/de-73CTH2E4.cjs.map +1 -0
- package/dist/de-GUUJUHYP.js +2 -0
- package/dist/de-GUUJUHYP.js.map +1 -0
- package/dist/deep-link.d.cts +14 -0
- package/dist/deep-link.d.ts +14 -0
- package/dist/email.d.cts +6 -3
- package/dist/email.d.ts +6 -3
- package/dist/errors.d.cts +18 -4
- package/dist/errors.d.ts +18 -4
- package/dist/{es-HEVFJPRI.js → es-3MXMSDUC.js} +2 -2
- package/dist/es-3MXMSDUC.js.map +1 -0
- package/dist/{es-5XQA3TPT.cjs → es-WJZ3XARH.cjs} +2 -2
- package/dist/es-WJZ3XARH.cjs.map +1 -0
- package/dist/filters.d.cts +31 -7
- package/dist/filters.d.ts +31 -7
- package/dist/fr-52F3ZCLQ.js +2 -0
- package/dist/fr-52F3ZCLQ.js.map +1 -0
- package/dist/fr-ZCRIJWI3.cjs +2 -0
- package/dist/fr-ZCRIJWI3.cjs.map +1 -0
- package/dist/i18n.d.cts +18 -0
- package/dist/i18n.d.ts +18 -0
- package/dist/index.cjs +3 -1588
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.global.js +4 -3389
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +3 -1588
- package/dist/index.js.map +1 -1
- package/dist/it-MEUT3RCC.js +2 -0
- package/dist/it-MEUT3RCC.js.map +1 -0
- package/dist/it-TGUTW6MO.cjs +2 -0
- package/dist/it-TGUTW6MO.cjs.map +1 -0
- package/dist/ja-DOS7AWLW.cjs +2 -0
- package/dist/ja-DOS7AWLW.cjs.map +1 -0
- package/dist/ja-U7NRNGPQ.js +2 -0
- package/dist/ja-U7NRNGPQ.js.map +1 -0
- package/dist/panel-HGYK7HVK.cjs +2 -0
- package/dist/panel-HGYK7HVK.cjs.map +1 -0
- package/dist/panel-RE2IHZ4S.js +2 -0
- package/dist/panel-RE2IHZ4S.js.map +1 -0
- package/dist/panel-RHSIY6KS.cjs +2 -0
- package/dist/panel-RHSIY6KS.cjs.map +1 -0
- package/dist/panel-XVIF2WMU.js +2 -0
- package/dist/panel-XVIF2WMU.js.map +1 -0
- package/dist/pt-BZRBHCYN.cjs +2 -0
- package/dist/pt-BZRBHCYN.cjs.map +1 -0
- package/dist/pt-MOS5DVOG.js +2 -0
- package/dist/pt-MOS5DVOG.js.map +1 -0
- package/dist/react.cjs +3 -1588
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +3 -1588
- package/dist/react.js.map +1 -1
- package/dist/ru-KDNRHHNZ.cjs +2 -0
- package/dist/ru-KDNRHHNZ.cjs.map +1 -0
- package/dist/ru-VSWB5NKK.js +2 -0
- package/dist/ru-VSWB5NKK.js.map +1 -0
- package/dist/schema.d.cts +54 -0
- package/dist/schema.d.ts +54 -0
- package/dist/screenshot-storage.d.cts +61 -19
- package/dist/screenshot-storage.d.ts +61 -19
- package/dist/siteping-core.d.cts +9 -6
- package/dist/siteping-core.d.ts +9 -6
- package/dist/store-helpers.d.cts +59 -15
- package/dist/store-helpers.d.ts +59 -15
- package/dist/type-utils.d.cts +8 -0
- package/dist/type-utils.d.ts +8 -0
- package/dist/types.d.cts +399 -33
- package/dist/types.d.ts +399 -33
- package/dist/wire.d.cts +35 -2
- package/dist/wire.d.ts +35 -2
- package/package.json +3 -1
- package/dist/chunk-AFLWWD6M.cjs +0 -1796
- package/dist/chunk-AFLWWD6M.cjs.map +0 -1
- package/dist/chunk-ATTI2TS4.js +0 -1796
- package/dist/chunk-ATTI2TS4.js.map +0 -1
- package/dist/chunk-BP5TH2CD.js +0 -1796
- package/dist/chunk-BP5TH2CD.js.map +0 -1
- package/dist/chunk-OSADAHGS.cjs +0 -1796
- package/dist/chunk-OSADAHGS.cjs.map +0 -1
- package/dist/de-AZUOIGF2.cjs +0 -2
- package/dist/de-AZUOIGF2.cjs.map +0 -1
- package/dist/de-MAGIJBFC.js +0 -2
- package/dist/de-MAGIJBFC.js.map +0 -1
- package/dist/es-5XQA3TPT.cjs.map +0 -1
- package/dist/es-HEVFJPRI.js.map +0 -1
- package/dist/fr-ERYSAH32.cjs +0 -2
- package/dist/fr-ERYSAH32.cjs.map +0 -1
- package/dist/fr-OM2PHLDH.js +0 -2
- package/dist/fr-OM2PHLDH.js.map +0 -1
- package/dist/it-NXAZR4K6.cjs +0 -2
- package/dist/it-NXAZR4K6.cjs.map +0 -1
- package/dist/it-OQVYHKKV.js +0 -2
- package/dist/it-OQVYHKKV.js.map +0 -1
- package/dist/panel-2FEECS2N.cjs +0 -2
- package/dist/panel-2FEECS2N.cjs.map +0 -1
- package/dist/panel-CSFFA5FF.cjs +0 -2
- package/dist/panel-CSFFA5FF.cjs.map +0 -1
- package/dist/panel-S2UR5BSD.js +0 -2
- package/dist/panel-S2UR5BSD.js.map +0 -1
- package/dist/panel-SGSUHR7V.js +0 -2
- package/dist/panel-SGSUHR7V.js.map +0 -1
- package/dist/pt-CODDT6VY.cjs +0 -2
- package/dist/pt-CODDT6VY.cjs.map +0 -1
- package/dist/pt-VUUNL42H.js +0 -2
- package/dist/pt-VUUNL42H.js.map +0 -1
- package/dist/ru-72WUEADV.cjs +0 -2
- package/dist/ru-72WUEADV.cjs.map +0 -1
- package/dist/ru-NDWY7Y36.js +0 -2
- package/dist/ru-NDWY7Y36.js.map +0 -1
package/dist/types.d.cts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { type Prettify, type Serialized } from "./type-utils.cjs";
|
|
1
|
+
import { type DeepReadonly, type Prettify, type Serialized } from "./type-utils.cjs";
|
|
2
2
|
/** FAB anchor — bottom-corner placement supported by the widget. */
|
|
3
3
|
export type SitepingPosition = "bottom-right" | "bottom-left";
|
|
4
4
|
/** Visual theme — `auto` resolves to `light` or `dark` via system preference. */
|
|
5
5
|
export type SitepingTheme = "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
|
|
@@ -14,14 +14,17 @@ export type BuiltinLocale = (typeof BUILTIN_LOCALES)[number];
|
|
|
14
14
|
export type SitepingLocale = BuiltinLocale | (string & {});
|
|
15
15
|
/**
|
|
16
16
|
* Reasons reported through `SitepingConfig.onSkip` — production environment,
|
|
17
|
-
*
|
|
17
|
+
* viewport narrower than `minViewportWidth` (`"mobile"`), or server-side
|
|
18
|
+
* rendering (no `window`/`document`).
|
|
18
19
|
*/
|
|
19
20
|
export type SitepingSkipReason = "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. */
|
|
@@ -29,11 +32,104 @@ export interface SitepingIdentity {
|
|
|
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
42
|
export interface SitepingDeepLinkOptions {
|
|
34
43
|
/** Query parameter name carrying the feedback id. Defaults to `"siteping"`. */
|
|
35
44
|
param?: string | undefined;
|
|
36
45
|
}
|
|
46
|
+
/**
|
|
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.
|
|
50
|
+
*/
|
|
51
|
+
export type SitepingPanelActionFeedback = DeepReadonly<FeedbackResponse>;
|
|
52
|
+
/**
|
|
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 SitepingPanelActionContext {
|
|
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 SitepingPanelAction}.
|
|
69
|
+
*
|
|
70
|
+
* Do not use this type directly — use {@link SitepingPanelAction}.
|
|
71
|
+
*/
|
|
72
|
+
export interface SitepingPanelActionBase {
|
|
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: SitepingPanelActionFeedback) => boolean) | undefined;
|
|
93
|
+
}
|
|
94
|
+
/** A panel action rendered as a button that runs host code. */
|
|
95
|
+
export interface SitepingPanelButtonAction extends SitepingPanelActionBase {
|
|
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: SitepingPanelActionFeedback, context: SitepingPanelActionContext) => 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 SitepingPanelLinkAction extends SitepingPanelActionBase {
|
|
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: SitepingPanelActionFeedback) => string);
|
|
119
|
+
/** Not available on a link action — use either `onAction` or `href`, never both. */
|
|
120
|
+
onAction?: never;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
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.
|
|
126
|
+
*
|
|
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.
|
|
131
|
+
*/
|
|
132
|
+
export type SitepingPanelAction = SitepingPanelButtonAction | SitepingPanelLinkAction;
|
|
37
133
|
/**
|
|
38
134
|
* Extra request headers for HTTP mode — a static map, or a factory (sync or
|
|
39
135
|
* async) invoked once per request to produce fresh values (e.g. a short-lived
|
|
@@ -69,7 +165,7 @@ export interface SitepingBaseConfig {
|
|
|
69
165
|
accentColor?: string | undefined;
|
|
70
166
|
/**
|
|
71
167
|
* Render the widget even when it would normally be skipped — this bypasses
|
|
72
|
-
* BOTH the production-environment guard AND the
|
|
168
|
+
* BOTH the production-environment guard AND the `minViewportWidth` guard.
|
|
73
169
|
* It does NOT bypass the SSR guard: without `window`/`document` the widget
|
|
74
170
|
* never renders and `onSkip("ssr")` fires instead.
|
|
75
171
|
* Defaults to false. Use it for dedicated review tools, staging environments,
|
|
@@ -78,17 +174,19 @@ export interface SitepingBaseConfig {
|
|
|
78
174
|
forceShow?: boolean | undefined;
|
|
79
175
|
/**
|
|
80
176
|
* Minimum viewport width (px) at or above which the widget renders. Below it,
|
|
81
|
-
* 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).
|
|
82
180
|
*
|
|
83
|
-
* Set
|
|
84
|
-
* 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.
|
|
85
183
|
*/
|
|
86
184
|
minViewportWidth?: number | undefined;
|
|
87
185
|
/** Enable debug logging of lifecycle events — defaults to false */
|
|
88
186
|
debug?: boolean | undefined;
|
|
89
187
|
/** Color theme — defaults to 'light' */
|
|
90
188
|
theme?: SitepingTheme | undefined;
|
|
91
|
-
/** UI locale — defaults to 'en'. Built-in: en, fr, de, es, it, pt (Brazilian), ru. Any other string falls back to English. */
|
|
189
|
+
/** UI locale — defaults to 'en'. Built-in: en, fr, de, es, it, pt (Brazilian), ru, ja. Any other string falls back to English. */
|
|
92
190
|
locale?: SitepingLocale | undefined;
|
|
93
191
|
/**
|
|
94
192
|
* Returns the current page scope for annotations and panel filtering.
|
|
@@ -139,7 +237,8 @@ export interface SitepingBaseConfig {
|
|
|
139
237
|
*
|
|
140
238
|
* Keyboard-triggered context menus (≣ Menu key, Shift+F10) always get the
|
|
141
239
|
* native menu; only mouse right-click and touch/pen long-press open the
|
|
142
|
-
* 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).
|
|
143
242
|
*
|
|
144
243
|
* **Modifier-key escape hatch:** holding Shift, Ctrl, Alt, or Meta while
|
|
145
244
|
* right-clicking always falls through to the native context menu, giving
|
|
@@ -148,9 +247,11 @@ export interface SitepingBaseConfig {
|
|
|
148
247
|
* Right-clicks on SitePing's own UI (FAB, panel, markers, popup) are
|
|
149
248
|
* ignored — the native menu is shown as expected.
|
|
150
249
|
*
|
|
151
|
-
* Note: on Android, `contextmenu` fires on long-press
|
|
152
|
-
*
|
|
153
|
-
*
|
|
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.
|
|
154
255
|
*/
|
|
155
256
|
enableRightClickComment?: boolean | undefined;
|
|
156
257
|
/**
|
|
@@ -163,15 +264,18 @@ export interface SitepingBaseConfig {
|
|
|
163
264
|
*
|
|
164
265
|
* - `true` — capture with defaults (50 console / 20 network entries).
|
|
165
266
|
* - `false` (default) — no capture, no monkey-patching.
|
|
166
|
-
* - 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).
|
|
167
269
|
*
|
|
168
270
|
* **Privacy considerations:** console messages may contain anything the
|
|
169
271
|
* host page logs, including user data. Failed network requests record the
|
|
170
|
-
* URL
|
|
171
|
-
*
|
|
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.
|
|
172
276
|
*/
|
|
173
277
|
captureDiagnostics?: boolean | DiagnosticsCaptureOptions | undefined;
|
|
174
|
-
/** Called when the widget is skipped (production mode,
|
|
278
|
+
/** Called when the widget is skipped (production mode, viewport under `minViewportWidth`, SSR — no DOM) */
|
|
175
279
|
onSkip?: (reason: SitepingSkipReason) => void;
|
|
176
280
|
/**
|
|
177
281
|
* Auto-focus a specific annotation when its ID appears in the URL query
|
|
@@ -239,12 +343,30 @@ export interface SitepingBaseConfig {
|
|
|
239
343
|
* future enhancement that propagates identity updates without a remount.
|
|
240
344
|
*/
|
|
241
345
|
identity?: SitepingIdentity | 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 SitepingPanelAction}.
|
|
352
|
+
*/
|
|
353
|
+
panelActions?: readonly SitepingPanelAction[] | 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;
|
|
242
362
|
/** Called when the feedback panel is opened. */
|
|
243
363
|
onOpen?: (() => void) | undefined;
|
|
244
364
|
/** Called when the feedback panel is closed. */
|
|
245
365
|
onClose?: (() => void) | undefined;
|
|
246
366
|
/** Called after a feedback is successfully submitted. */
|
|
247
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;
|
|
248
370
|
/**
|
|
249
371
|
* Called when a feedback API call fails.
|
|
250
372
|
*
|
|
@@ -252,9 +374,16 @@ export interface SitepingBaseConfig {
|
|
|
252
374
|
* `SitepingNetworkError`, `SitepingValidationError`, `SitepingAuthError`)
|
|
253
375
|
* for HTTP-mode failures — host apps can `instanceof` to drive retry
|
|
254
376
|
* logic, or read `error.code` (`"NETWORK" | "VALIDATION" | "AUTH" |
|
|
255
|
-
* "SERVER"`) and `error.retryable
|
|
256
|
-
*
|
|
257
|
-
*
|
|
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.
|
|
258
387
|
*/
|
|
259
388
|
onError?: ((error: Error) => void) | undefined;
|
|
260
389
|
/** Called when the user starts drawing an annotation. */
|
|
@@ -283,9 +412,10 @@ export interface SitepingHttpConfig extends SitepingBaseConfig {
|
|
|
283
412
|
/**
|
|
284
413
|
* Extra headers for every HTTP-mode request — a static map, or a factory
|
|
285
414
|
* (sync or async) called once per request (e.g. to fetch a fresh session
|
|
286
|
-
* token). Merged over the widget's generated headers,
|
|
287
|
-
* `Authorization` entry overrides `apiKey`. A
|
|
288
|
-
* fails the request like a
|
|
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.
|
|
289
419
|
*/
|
|
290
420
|
headers?: SitepingHeadersOption | undefined;
|
|
291
421
|
/** Not available in HTTP mode — use either `endpoint` or `store`, never both. */
|
|
@@ -296,7 +426,11 @@ export interface SitepingHttpConfig extends SitepingBaseConfig {
|
|
|
296
426
|
* browser, no server needed (demos, prototypes, localStorage persistence).
|
|
297
427
|
*/
|
|
298
428
|
export interface SitepingStoreConfig extends SitepingBaseConfig {
|
|
299
|
-
/**
|
|
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
|
+
*/
|
|
300
434
|
store: SitepingStore;
|
|
301
435
|
/** Not available in store mode — use either `endpoint` or `store`, never both. */
|
|
302
436
|
endpoint?: never;
|
|
@@ -348,6 +482,8 @@ export type SitepingUnsubscribe = () => void;
|
|
|
348
482
|
export interface SitepingPublicEvents {
|
|
349
483
|
"feedback:sent": [FeedbackResponse];
|
|
350
484
|
"feedback:deleted": [FeedbackResponse["id"]];
|
|
485
|
+
/** A reply was posted from the panel's discussion thread. */
|
|
486
|
+
"comment:added": [CommentResponse];
|
|
351
487
|
/**
|
|
352
488
|
* A feedback API call failed. Same payload contract as
|
|
353
489
|
* `SitepingConfig.onError` — a `SitepingError` subclass in HTTP mode,
|
|
@@ -482,6 +618,11 @@ export interface FeedbackQuery {
|
|
|
482
618
|
statuses?: readonly FeedbackStatus[] | undefined;
|
|
483
619
|
search?: string | undefined;
|
|
484
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
|
+
*/
|
|
485
626
|
limit?: number | undefined;
|
|
486
627
|
/**
|
|
487
628
|
* Filter to feedbacks created on this exact URL (path). Used by the panel's
|
|
@@ -540,6 +681,13 @@ export interface FeedbackRecord {
|
|
|
540
681
|
createdAt: Date;
|
|
541
682
|
updatedAt: Date;
|
|
542
683
|
annotations: AnnotationRecord[];
|
|
684
|
+
/**
|
|
685
|
+
* Discussion thread, oldest first. A store that implements
|
|
686
|
+
* `SitepingStore.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;
|
|
543
691
|
/**
|
|
544
692
|
* URL the widget renders as `<img src>`. Either an `https://...` from a
|
|
545
693
|
* configured `ScreenshotStorage`, or a `data:image/jpeg;base64,...` URL
|
|
@@ -587,6 +735,66 @@ export interface AnnotationRecord {
|
|
|
587
735
|
devicePixelRatio: number;
|
|
588
736
|
createdAt: Date;
|
|
589
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 `SitepingStore.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
|
+
}
|
|
590
798
|
/**
|
|
591
799
|
* Thrown when a record is not found during update or delete.
|
|
592
800
|
*
|
|
@@ -616,14 +824,41 @@ export declare class StorePersistenceError extends Error {
|
|
|
616
824
|
readonly code: "STORE_PERSISTENCE";
|
|
617
825
|
constructor(message?: string, options?: ErrorOptions);
|
|
618
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
|
+
}
|
|
619
846
|
/** Shape of any ORM error that carries a Prisma-style `code` field. */
|
|
620
847
|
type CodedError<C extends string = string> = {
|
|
621
848
|
code: C;
|
|
622
849
|
};
|
|
623
|
-
/**
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
850
|
+
/**
|
|
851
|
+
* Type guard — works for `StoreNotFoundError` and ORM-specific equivalents
|
|
852
|
+
* (e.g. Prisma P2025). Matches on the stable `code` too, for the same
|
|
853
|
+
* cross-bundle reason as {@link isStorePersistence}.
|
|
854
|
+
*/
|
|
855
|
+
export declare function isStoreNotFound(error: unknown): error is StoreNotFoundError | CodedError<"STORE_NOT_FOUND" | "P2025">;
|
|
856
|
+
/**
|
|
857
|
+
* Type guard — works for `StoreDuplicateError` and ORM-specific equivalents
|
|
858
|
+
* (e.g. Prisma P2002). Matches on the stable `code` too, for the same
|
|
859
|
+
* cross-bundle reason as {@link isStorePersistence}.
|
|
860
|
+
*/
|
|
861
|
+
export declare function isStoreDuplicate(error: unknown): error is StoreDuplicateError | CodedError<"STORE_DUPLICATE" | "P2002">;
|
|
627
862
|
/**
|
|
628
863
|
* Type guard for `StorePersistenceError`. Matches on the stable `code` field
|
|
629
864
|
* in addition to `instanceof`: every consumer package bundles its own copy of
|
|
@@ -631,8 +866,25 @@ export declare function isStoreDuplicate(error: unknown): error is StoreDuplicat
|
|
|
631
866
|
* `instanceof` check against another package's class identity.
|
|
632
867
|
*/
|
|
633
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">;
|
|
634
873
|
/** Flatten a widget `AnnotationPayload` (nested anchor + rect) into a flat `AnnotationCreateInput`. */
|
|
635
874
|
export declare function flattenAnnotation(ann: AnnotationPayload): AnnotationCreateInput;
|
|
875
|
+
/**
|
|
876
|
+
* Outcome of `SitepingStore.createFeedbackIfAbsent` — the record plus whether
|
|
877
|
+
* this very call inserted it.
|
|
878
|
+
*/
|
|
879
|
+
export interface FeedbackCreateOutcome {
|
|
880
|
+
feedback: FeedbackRecord;
|
|
881
|
+
/**
|
|
882
|
+
* `true` when this call inserted the record, `false` when a record with the
|
|
883
|
+
* same `clientId` already existed and is returned instead (a replay, or a
|
|
884
|
+
* concurrent request that won the race).
|
|
885
|
+
*/
|
|
886
|
+
created: boolean;
|
|
887
|
+
}
|
|
636
888
|
/** Paginated result returned by `SitepingStore.getFeedbacks`. */
|
|
637
889
|
export interface FeedbackPage {
|
|
638
890
|
feedbacks: FeedbackRecord[];
|
|
@@ -651,7 +903,10 @@ export interface FeedbackPage {
|
|
|
651
903
|
* the record does not exist.
|
|
652
904
|
* - **`createFeedback`**: either return the existing record on duplicate
|
|
653
905
|
* `clientId` (idempotent) or throw `StoreDuplicateError`. The handler
|
|
654
|
-
* handles both patterns
|
|
906
|
+
* handles both patterns — but only a throw, or the optional
|
|
907
|
+
* `createFeedbackIfAbsent`, tells it the record was not inserted by this
|
|
908
|
+
* call; stores that return the existing record should implement
|
|
909
|
+
* `createFeedbackIfAbsent` so creation side effects never run twice.
|
|
655
910
|
* - **All mutations**: when a write is accepted but cannot be persisted
|
|
656
911
|
* (e.g. storage quota), throw `StorePersistenceError` instead of reporting
|
|
657
912
|
* a phantom success. Detect it with `isStorePersistence`.
|
|
@@ -679,6 +934,51 @@ export interface SitepingStore {
|
|
|
679
934
|
* handlers skip the ownership check and rely on `id` alone.
|
|
680
935
|
*/
|
|
681
936
|
verifyProjectOwnership?(id: string, projectName: string): Promise<boolean>;
|
|
937
|
+
/**
|
|
938
|
+
* Optional — `createFeedback` that reports whether this call inserted the
|
|
939
|
+
* record (`created: true`) or found an existing one with the same
|
|
940
|
+
* `clientId` (`created: false`). The dedup check and the insert must be
|
|
941
|
+
* atomic, like `createFeedback`'s: of N concurrent calls with the same
|
|
942
|
+
* `clientId`, exactly one may report `created: true`, and all must return
|
|
943
|
+
* that same record. `createCollectionStore` guarantees this within one
|
|
944
|
+
* store instance by serializing its mutations; stores shared across
|
|
945
|
+
* processes need an atomic backend primitive (unique constraint,
|
|
946
|
+
* transaction, compare-and-set).
|
|
947
|
+
*
|
|
948
|
+
* HTTP handlers prefer it over `createFeedback` to fire creation side
|
|
949
|
+
* effects (webhooks) exactly once when concurrent requests race on the
|
|
950
|
+
* same `clientId`. Stores whose `createFeedback` throws
|
|
951
|
+
* `StoreDuplicateError` on a duplicate already give that signal and may
|
|
952
|
+
* leave it out.
|
|
953
|
+
*/
|
|
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>;
|
|
682
982
|
}
|
|
683
983
|
/** Payload sent from the widget to the server when submitting feedback. */
|
|
684
984
|
export interface FeedbackPayload {
|
|
@@ -750,11 +1050,26 @@ export interface DiagnosticsSnapshot {
|
|
|
750
1050
|
console: ConsoleDiagnosticEntry[];
|
|
751
1051
|
network: NetworkDiagnosticEntry[];
|
|
752
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;
|
|
753
1061
|
/** DOM anchoring data for re-attaching annotations to page elements. */
|
|
754
1062
|
export interface AnchorData {
|
|
755
|
-
/**
|
|
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
|
+
*/
|
|
756
1068
|
cssSelector: string;
|
|
757
|
-
/**
|
|
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
|
+
*/
|
|
758
1073
|
xpath: string;
|
|
759
1074
|
/** First ~120 chars of element innerText — empty string if none */
|
|
760
1075
|
textSnippet: string;
|
|
@@ -819,22 +1134,73 @@ export interface AnnotationPayload {
|
|
|
819
1134
|
/**
|
|
820
1135
|
* Feedback record as returned by the API — derived from
|
|
821
1136
|
* {@link FeedbackRecord}: dates are serialized to ISO strings and `clientId`
|
|
822
|
-
* is omitted (server-side dedup concern, never exposed on the wire)
|
|
823
|
-
*
|
|
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.
|
|
824
1140
|
*
|
|
825
1141
|
* Note: `authorEmail` may be an empty string — HTTP adapters redact it for
|
|
826
1142
|
* unauthenticated requests; the full value requires a Bearer-authenticated
|
|
827
1143
|
* request.
|
|
828
1144
|
*/
|
|
829
|
-
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 `@siteping/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
|
+
* `@siteping/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
|
+
}
|
|
830
1175
|
/**
|
|
831
1176
|
* Annotation record as returned by the API — {@link AnnotationRecord} with
|
|
832
1177
|
* `createdAt` serialized to an ISO string.
|
|
833
1178
|
*/
|
|
834
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 SitepingCapabilities {
|
|
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 `@siteping/server`; a client that does not delete (the widget)
|
|
1193
|
+
* leaves it out.
|
|
1194
|
+
*/
|
|
1195
|
+
deleteComments?: boolean | undefined;
|
|
1196
|
+
}
|
|
835
1197
|
/** Paginated `FeedbackResponse` shape returned by the API. */
|
|
836
1198
|
export interface FeedbackResponseList {
|
|
837
1199
|
feedbacks: FeedbackResponse[];
|
|
838
1200
|
total: number;
|
|
1201
|
+
/** Always sent by `@siteping/server` — absent from servers that predate it. */
|
|
1202
|
+
capabilities?: SitepingCapabilities | undefined;
|
|
1203
|
+
/** Always sent by `@siteping/server` — absent from servers that predate it. */
|
|
1204
|
+
permissions?: FeedbackListPermissions | undefined;
|
|
839
1205
|
}
|
|
840
1206
|
export {};
|