@siteping/widget 0.10.5 → 0.10.7

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.
Files changed (54) hide show
  1. package/README.md +25 -222
  2. package/dist/chunk-7ZBKJ6NW.js +1796 -0
  3. package/dist/chunk-7ZBKJ6NW.js.map +1 -0
  4. package/dist/chunk-FDQWFGRR.js +1796 -0
  5. package/dist/chunk-FDQWFGRR.js.map +1 -0
  6. package/dist/chunk-GKRKCSID.cjs +1796 -0
  7. package/dist/chunk-GKRKCSID.cjs.map +1 -0
  8. package/dist/chunk-NVNA5AI2.cjs +1796 -0
  9. package/dist/chunk-NVNA5AI2.cjs.map +1 -0
  10. package/dist/filters.d.cts +3 -1
  11. package/dist/filters.d.ts +3 -1
  12. package/dist/i18n.d.cts +67 -0
  13. package/dist/i18n.d.ts +67 -0
  14. package/dist/index.cjs +40 -40
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +152 -6
  17. package/dist/index.d.ts +152 -6
  18. package/dist/index.global.js +46 -46
  19. package/dist/index.global.js.map +1 -1
  20. package/dist/index.js +28 -28
  21. package/dist/index.js.map +1 -1
  22. package/dist/panel-7URHNKQH.js +2 -0
  23. package/dist/panel-7URHNKQH.js.map +1 -0
  24. package/dist/panel-FUPBUN6F.js +2 -0
  25. package/dist/panel-FUPBUN6F.js.map +1 -0
  26. package/dist/panel-M2QKMFYO.cjs +2 -0
  27. package/dist/panel-M2QKMFYO.cjs.map +1 -0
  28. package/dist/panel-XUTDVTAR.cjs +2 -0
  29. package/dist/panel-XUTDVTAR.cjs.map +1 -0
  30. package/dist/react.cjs +47 -47
  31. package/dist/react.cjs.map +1 -1
  32. package/dist/react.js +41 -41
  33. package/dist/react.js.map +1 -1
  34. package/dist/screenshot-storage.d.cts +5 -0
  35. package/dist/screenshot-storage.d.ts +5 -0
  36. package/dist/siteping-core.d.cts +8 -3
  37. package/dist/siteping-core.d.ts +8 -3
  38. package/dist/store-helpers.d.cts +87 -0
  39. package/dist/store-helpers.d.ts +87 -0
  40. package/dist/type-utils.d.cts +13 -44
  41. package/dist/type-utils.d.ts +13 -44
  42. package/dist/types.d.cts +147 -110
  43. package/dist/types.d.ts +147 -110
  44. package/dist/wire.d.cts +35 -0
  45. package/dist/wire.d.ts +35 -0
  46. package/package.json +2 -1
  47. package/dist/chunk-D2AVRF24.js +0 -1796
  48. package/dist/chunk-D2AVRF24.js.map +0 -1
  49. package/dist/chunk-GRKBXAGP.cjs +0 -1796
  50. package/dist/chunk-GRKBXAGP.cjs.map +0 -1
  51. package/dist/panel-LMVRKAQH.cjs +0 -2
  52. package/dist/panel-LMVRKAQH.cjs.map +0 -1
  53. package/dist/panel-OXUE7PJY.js +0 -2
  54. package/dist/panel-OXUE7PJY.js.map +0 -1
package/dist/types.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { type Prettify } from "./type-utils.cjs";
1
+ import { 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. */
@@ -19,10 +19,10 @@ export type SitepingLocale = BuiltinLocale | (string & {});
19
19
  export type SitepingSkipReason = "production" | "mobile" | "ssr";
20
20
  /** Per-channel + per-buffer-size diagnostics configuration. */
21
21
  export interface DiagnosticsCaptureOptions {
22
- console?: boolean;
23
- network?: boolean;
24
- maxConsoleEntries?: number;
25
- maxNetworkEntries?: number;
22
+ console?: boolean | undefined;
23
+ network?: boolean | undefined;
24
+ maxConsoleEntries?: number | undefined;
25
+ maxNetworkEntries?: number | undefined;
26
26
  }
27
27
  /** Identity payload supplied by the host application — bypasses the modal. */
28
28
  export interface SitepingIdentity {
@@ -32,7 +32,7 @@ export interface SitepingIdentity {
32
32
  /** Deep-link configuration — controls how a feedback id is read from the URL. */
33
33
  export interface SitepingDeepLinkOptions {
34
34
  /** Query parameter name carrying the feedback id. Defaults to `"siteping"`. */
35
- param?: string;
35
+ param?: string | undefined;
36
36
  }
37
37
  /**
38
38
  * Extra request headers for HTTP mode — a static map, or a factory (sync or
@@ -40,39 +40,17 @@ export interface SitepingDeepLinkOptions {
40
40
  * session token).
41
41
  */
42
42
  export type SitepingHeadersOption = Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
43
- /** Configuration options for the Siteping widget. */
44
- export interface SitepingConfig {
45
- /** HTTP endpoint that receives feedbacks (e.g. '/api/siteping'). Required unless `store` is provided. */
46
- endpoint?: string | undefined;
47
- /**
48
- * Convenience auth for HTTP mode — sent as `Authorization: Bearer <apiKey>`
49
- * on every request to `endpoint`.
50
- *
51
- * **WARNING: the widget runs in every visitor's browser, so a static key
52
- * configured here is public** — anyone can read it from your page source
53
- * and replay it against your API. Only use `apiKey` for internal tools
54
- * already behind your own login. On public sites, prefer `headers` with a
55
- * per-request factory returning a short-lived session token.
56
- *
57
- * Ignored in store mode.
58
- */
59
- apiKey?: string | undefined;
60
- /**
61
- * Extra headers for every HTTP-mode request — a static map, or a factory
62
- * (sync or async) called once per request (e.g. to fetch a fresh session
63
- * token). Merged over the widget's generated headers, so an explicit
64
- * `Authorization` entry overrides `apiKey`. A throwing/rejecting factory
65
- * fails the request like a network error.
66
- *
67
- * Ignored in store mode.
68
- */
69
- headers?: SitepingHeadersOption | undefined;
43
+ /**
44
+ * Options shared by both widget modes (HTTP and direct store).
45
+ *
46
+ * Do not use this type directly — use {@link SitepingConfig}, the
47
+ * discriminated union that adds the mode-specific fields.
48
+ */
49
+ export interface SitepingBaseConfig {
70
50
  /** Required — project identifier used to scope feedbacks */
71
51
  projectName: string;
72
- /** Direct store for client-side mode. When set, bypasses HTTP and uses the store directly in the browser. */
73
- store?: SitepingStore | undefined;
74
52
  /** FAB position — defaults to 'bottom-right' */
75
- position?: SitepingPosition;
53
+ position?: SitepingPosition | undefined;
76
54
  /**
77
55
  * Show the "toggle markers visibility" item in the FAB radial menu.
78
56
  * Defaults to `true` (current behavior). Set to `false` to hide that
@@ -88,7 +66,7 @@ export interface SitepingConfig {
88
66
  */
89
67
  showAnnotationsToggle?: boolean | undefined;
90
68
  /** Accent color for the widget UI — defaults to '#0066ff' */
91
- accentColor?: string;
69
+ accentColor?: string | undefined;
92
70
  /**
93
71
  * Render the widget even when it would normally be skipped — this bypasses
94
72
  * BOTH the production-environment guard AND the mobile-viewport guard.
@@ -97,7 +75,7 @@ export interface SitepingConfig {
97
75
  * Defaults to false. Use it for dedicated review tools, staging environments,
98
76
  * or responsive testing where you always want the widget present.
99
77
  */
100
- forceShow?: boolean;
78
+ forceShow?: boolean | undefined;
101
79
  /**
102
80
  * Minimum viewport width (px) at or above which the widget renders. Below it,
103
81
  * the widget is skipped and `onSkip("mobile")` fires. Defaults to `768`.
@@ -107,9 +85,9 @@ export interface SitepingConfig {
107
85
  */
108
86
  minViewportWidth?: number | undefined;
109
87
  /** Enable debug logging of lifecycle events — defaults to false */
110
- debug?: boolean;
88
+ debug?: boolean | undefined;
111
89
  /** Color theme — defaults to 'light' */
112
- theme?: SitepingTheme;
90
+ theme?: SitepingTheme | undefined;
113
91
  /** UI locale — defaults to 'en'. Built-in: en, fr, de, es, it, pt (Brazilian), ru. Any other string falls back to English. */
114
92
  locale?: SitepingLocale | undefined;
115
93
  /**
@@ -262,10 +240,11 @@ export interface SitepingConfig {
262
240
  */
263
241
  identity?: SitepingIdentity | undefined;
264
242
  /** Called when the feedback panel is opened. */
265
- onOpen?: () => void;
243
+ onOpen?: (() => void) | undefined;
266
244
  /** Called when the feedback panel is closed. */
267
- onClose?: () => void;
268
- onFeedbackSent?: (feedback: FeedbackResponse) => void;
245
+ onClose?: (() => void) | undefined;
246
+ /** Called after a feedback is successfully submitted. */
247
+ onFeedbackSent?: ((feedback: FeedbackResponse) => void) | undefined;
269
248
  /**
270
249
  * Called when a feedback API call fails.
271
250
  *
@@ -277,12 +256,64 @@ export interface SitepingConfig {
277
256
  * direct-store callers can still surface raw errors without breaking the
278
257
  * contract.
279
258
  */
280
- onError?: (error: Error) => void;
259
+ onError?: ((error: Error) => void) | undefined;
281
260
  /** Called when the user starts drawing an annotation. */
282
- onAnnotationStart?: () => void;
261
+ onAnnotationStart?: (() => void) | undefined;
283
262
  /** Called when the user finishes drawing an annotation. */
284
- onAnnotationEnd?: () => void;
263
+ onAnnotationEnd?: (() => void) | undefined;
285
264
  }
265
+ /**
266
+ * HTTP mode — the widget talks to a server endpoint backed by a store
267
+ * adapter (e.g. `@siteping/adapter-prisma` request handlers).
268
+ */
269
+ export interface SitepingHttpConfig extends SitepingBaseConfig {
270
+ /** HTTP endpoint that receives feedbacks (e.g. '/api/siteping'). */
271
+ endpoint: string;
272
+ /**
273
+ * Convenience auth for HTTP mode — sent as `Authorization: Bearer <apiKey>`
274
+ * on every request to `endpoint`.
275
+ *
276
+ * **WARNING: the widget runs in every visitor's browser, so a static key
277
+ * configured here is public** — anyone can read it from your page source
278
+ * and replay it against your API. Only use `apiKey` for internal tools
279
+ * already behind your own login. On public sites, prefer `headers` with a
280
+ * per-request factory returning a short-lived session token.
281
+ */
282
+ apiKey?: string | undefined;
283
+ /**
284
+ * Extra headers for every HTTP-mode request — a static map, or a factory
285
+ * (sync or async) called once per request (e.g. to fetch a fresh session
286
+ * token). Merged over the widget's generated headers, so an explicit
287
+ * `Authorization` entry overrides `apiKey`. A throwing/rejecting factory
288
+ * fails the request like a network error.
289
+ */
290
+ headers?: SitepingHeadersOption | undefined;
291
+ /** Not available in HTTP mode — use either `endpoint` or `store`, never both. */
292
+ store?: never;
293
+ }
294
+ /**
295
+ * Store mode — the widget talks to a `SitepingStore` directly in the
296
+ * browser, no server needed (demos, prototypes, localStorage persistence).
297
+ */
298
+ export interface SitepingStoreConfig extends SitepingBaseConfig {
299
+ /** Direct store for client-side mode. Bypasses HTTP entirely. */
300
+ store: SitepingStore;
301
+ /** Not available in store mode — use either `endpoint` or `store`, never both. */
302
+ endpoint?: never;
303
+ /** HTTP-mode only — meaningless without an `endpoint`. */
304
+ apiKey?: never;
305
+ /** HTTP-mode only — meaningless without an `endpoint`. */
306
+ headers?: never;
307
+ }
308
+ /**
309
+ * Configuration options for the Siteping widget.
310
+ *
311
+ * A discriminated union over the two transport modes: pass `endpoint`
312
+ * (HTTP mode, optionally with `apiKey`/`headers`) **or** `store` (direct
313
+ * client-side mode) — never both, never neither. Invalid combinations are
314
+ * compile errors instead of runtime warnings.
315
+ */
316
+ export type SitepingConfig = SitepingHttpConfig | SitepingStoreConfig;
286
317
  /** Instance returned by initSiteping() with lifecycle methods. */
287
318
  export interface SitepingInstance {
288
319
  /** Remove the widget from the DOM and clean up all listeners. */
@@ -317,8 +348,18 @@ export type SitepingUnsubscribe = () => void;
317
348
  export interface SitepingPublicEvents {
318
349
  "feedback:sent": [FeedbackResponse];
319
350
  "feedback:deleted": [FeedbackResponse["id"]];
351
+ /**
352
+ * A feedback API call failed. Same payload contract as
353
+ * `SitepingConfig.onError` — a `SitepingError` subclass in HTTP mode,
354
+ * possibly a raw `Error` in store mode.
355
+ */
356
+ "feedback:error": [Error];
320
357
  "panel:open": [];
321
358
  "panel:close": [];
359
+ /** The user started drawing an annotation. */
360
+ "annotation:start": [];
361
+ /** The user finished drawing an annotation. */
362
+ "annotation:end": [];
322
363
  }
323
364
  /** Single source of truth for feedback types — used by both TS types and Zod schemas. */
324
365
  export declare const FEEDBACK_TYPES: readonly ["question", "change", "bug", "other"];
@@ -333,8 +374,14 @@ export type FeedbackStatus = (typeof FEEDBACK_STATUSES)[number];
333
374
  * handler, dashboard) — store adapters persist whatever they are given.
334
375
  */
335
376
  export declare const CLOSED_FEEDBACK_STATUSES: readonly ["resolved", "wont_fix"];
336
- /** Whether a status is terminal (`resolved` or `wont_fix`). */
337
- export declare function isClosedStatus(status: FeedbackStatus): boolean;
377
+ /** A terminal status — `resolved` or `wont_fix`. */
378
+ export type ClosedFeedbackStatus = (typeof CLOSED_FEEDBACK_STATUSES)[number];
379
+ /** Non-terminal statuses — the feedback still needs attention. */
380
+ export declare const OPEN_FEEDBACK_STATUSES: readonly ["open", "in_progress"];
381
+ /** A non-terminal status — `open` or `in_progress`. */
382
+ export type OpenFeedbackStatus = (typeof OPEN_FEEDBACK_STATUSES)[number];
383
+ /** Whether a status is terminal (`resolved` or `wont_fix`). Narrows the status type. */
384
+ export declare function isClosedStatus(status: FeedbackStatus): status is ClosedFeedbackStatus;
338
385
  /**
339
386
  * Page scope returned by `SitepingConfig.getPageScope()`.
340
387
  *
@@ -448,11 +495,29 @@ export interface FeedbackQuery {
448
495
  */
449
496
  urlPattern?: string | undefined;
450
497
  }
451
- /** Update payload for patching a feedback. */
452
- export interface FeedbackUpdateInput {
453
- status: FeedbackStatus;
454
- resolvedAt: Date | null;
455
- }
498
+ /**
499
+ * Update payload for patching a feedback.
500
+ *
501
+ * A discriminated union encoding the closure invariant: a feedback entering
502
+ * a closed status carries its closure timestamp, an open one carries `null`.
503
+ * `{ status: "resolved", resolvedAt: null }` is a compile error instead of a
504
+ * silent data bug. Build it from a plain `FeedbackStatus` with
505
+ * {@link toFeedbackUpdate}.
506
+ */
507
+ export type FeedbackUpdateInput = {
508
+ status: OpenFeedbackStatus;
509
+ resolvedAt: null;
510
+ } | {
511
+ status: ClosedFeedbackStatus;
512
+ resolvedAt: Date;
513
+ };
514
+ /**
515
+ * Derive the {@link FeedbackUpdateInput} for a status change — the closure
516
+ * timestamp is stamped for closed statuses and cleared otherwise. This is
517
+ * the edge derivation described on {@link CLOSED_FEEDBACK_STATUSES}; store
518
+ * adapters persist the result verbatim.
519
+ */
520
+ export declare function toFeedbackUpdate(status: FeedbackStatus, closedAt?: Date): FeedbackUpdateInput;
456
521
  /** A persisted feedback record returned by the store. */
457
522
  export interface FeedbackRecord {
458
523
  id: string;
@@ -567,7 +632,7 @@ export declare function isStoreDuplicate(error: unknown): error is StoreDuplicat
567
632
  */
568
633
  export declare function isStorePersistence(error: unknown): error is StorePersistenceError | CodedError<"STORE_PERSISTENCE">;
569
634
  /** Flatten a widget `AnnotationPayload` (nested anchor + rect) into a flat `AnnotationCreateInput`. */
570
- export declare function flattenAnnotation(ann: AnnotationPayload): Prettify<AnnotationCreateInput>;
635
+ export declare function flattenAnnotation(ann: AnnotationPayload): AnnotationCreateInput;
571
636
  /** Paginated result returned by `SitepingStore.getFeedbacks`. */
572
637
  export interface FeedbackPage {
573
638
  feedbacks: FeedbackRecord[];
@@ -605,6 +670,15 @@ export interface SitepingStore {
605
670
  deleteFeedback(id: string): Promise<void>;
606
671
  /** Bulk delete all feedbacks for a project. No-op (not error) if none exist. Throws `StorePersistenceError` when the write cannot be persisted. */
607
672
  deleteAllFeedbacks(projectName: string): Promise<void>;
673
+ /**
674
+ * Optional — return `true` when the record with `id` belongs to
675
+ * `projectName`, `false` otherwise (including when it does not exist).
676
+ *
677
+ * HTTP handlers use this to reject cross-project PATCH/DELETE requests.
678
+ * Implement it whenever your store serves multiple projects; when absent,
679
+ * handlers skip the ownership check and rely on `id` alone.
680
+ */
681
+ verifyProjectOwnership?(id: string, projectName: string): Promise<boolean>;
608
682
  }
609
683
  /** Payload sent from the widget to the server when submitting feedback. */
610
684
  export interface FeedbackPayload {
@@ -642,8 +716,10 @@ export interface FeedbackPayload {
642
716
  */
643
717
  diagnostics?: DiagnosticsSnapshot | null | undefined;
644
718
  }
719
+ /** Single source of truth for console diagnostic severity levels. */
720
+ export declare const CONSOLE_DIAGNOSTIC_LEVELS: readonly ["log", "info", "warn", "error"];
645
721
  /** Severity levels persisted in `ConsoleDiagnosticEntry`. */
646
- export type ConsoleDiagnosticLevel = "log" | "info" | "warn" | "error";
722
+ export type ConsoleDiagnosticLevel = (typeof CONSOLE_DIAGNOSTIC_LEVELS)[number];
647
723
  /** A single console entry captured by `ConsoleBuffer`. */
648
724
  export interface ConsoleDiagnosticEntry {
649
725
  level: ConsoleDiagnosticLevel;
@@ -740,61 +816,22 @@ export interface AnnotationPayload {
740
816
  viewportH: number;
741
817
  devicePixelRatio: number;
742
818
  }
743
- /** Feedback record as returned by the API (dates serialized as strings). */
744
- export interface FeedbackResponse {
745
- id: string;
746
- projectName: string;
747
- type: FeedbackType;
748
- message: string;
749
- status: FeedbackStatus;
750
- url: string;
751
- /** Parameterized URL template the feedback was created on, or null. */
752
- urlPattern: string | null;
753
- viewport: string;
754
- userAgent: string;
755
- authorName: string;
756
- /**
757
- * May be an empty string — HTTP adapters redact it for unauthenticated
758
- * requests. The full value requires a Bearer-authenticated request.
759
- */
760
- authorEmail: string;
761
- resolvedAt: string | null;
762
- createdAt: string;
763
- updatedAt: string;
764
- annotations: AnnotationResponse[];
765
- /** Screenshot URL (data: or http:) — see `FeedbackRecord.screenshotUrl`. */
766
- screenshotUrl: string | null;
767
- /** Annotation rect within the screenshot image, or null — see `ScreenshotRegion`. */
768
- screenshotRegion: ScreenshotRegion | null;
769
- /** Console + failed-network snapshot, or null when diagnostics weren't captured. */
770
- diagnostics: DiagnosticsSnapshot | null;
771
- }
772
- /** Annotation record as returned by the API. */
773
- export interface AnnotationResponse {
774
- id: string;
775
- feedbackId: string;
776
- cssSelector: string;
777
- xpath: string;
778
- textSnippet: string;
779
- elementTag: string;
780
- elementId: string | null;
781
- textPrefix: string;
782
- textSuffix: string;
783
- fingerprint: string;
784
- neighborText: string;
785
- /** Semantic anchor identifier from `data-feedback-anchor`, or null. */
786
- anchorKey: string | null;
787
- xPct: number;
788
- yPct: number;
789
- wPct: number;
790
- hPct: number;
791
- scrollX: number;
792
- scrollY: number;
793
- viewportW: number;
794
- viewportH: number;
795
- devicePixelRatio: number;
796
- createdAt: string;
797
- }
819
+ /**
820
+ * Feedback record as returned by the API — derived from
821
+ * {@link FeedbackRecord}: dates are serialized to ISO strings and `clientId`
822
+ * is omitted (server-side dedup concern, never exposed on the wire). Adding
823
+ * a field to `FeedbackRecord` updates this type automatically.
824
+ *
825
+ * Note: `authorEmail` may be an empty string — HTTP adapters redact it for
826
+ * unauthenticated requests; the full value requires a Bearer-authenticated
827
+ * request.
828
+ */
829
+ export type FeedbackResponse = Prettify<Serialized<Omit<FeedbackRecord, "clientId">>>;
830
+ /**
831
+ * Annotation record as returned by the API — {@link AnnotationRecord} with
832
+ * `createdAt` serialized to an ISO string.
833
+ */
834
+ export type AnnotationResponse = Prettify<Serialized<AnnotationRecord>>;
798
835
  /** Paginated `FeedbackResponse` shape returned by the API. */
799
836
  export interface FeedbackResponseList {
800
837
  feedbacks: FeedbackResponse[];