@getpinax/widget 0.0.0-stage → 1.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +513 -2
  3. package/dist/a11y/scan.d.ts +25 -0
  4. package/dist/api.d.ts +83 -0
  5. package/dist/capture/breadcrumbs.d.ts +49 -0
  6. package/dist/capture/console.d.ts +17 -0
  7. package/dist/capture/env.d.ts +25 -0
  8. package/dist/capture/network.d.ts +23 -0
  9. package/dist/capture/ring.d.ts +14 -0
  10. package/dist/capture/signature.d.ts +7 -0
  11. package/dist/capture/text.d.ts +23 -0
  12. package/dist/capture/ua.d.ts +13 -0
  13. package/dist/chunks/editor-0Kr31Uly.mjs +1368 -0
  14. package/dist/chunks/privacy-B_b1_Y1n.mjs +39 -0
  15. package/dist/chunks/recorder-tu4yugLw.mjs +2874 -0
  16. package/dist/chunks/scan-CFQwrtAQ.mjs +46137 -0
  17. package/dist/chunks/text-D9SaDBT0.mjs +36 -0
  18. package/dist/chunks/widget-BpTBdX2R.mjs +1272 -0
  19. package/dist/editor/annotator.d.ts +20 -0
  20. package/dist/editor/capture.d.ts +28 -0
  21. package/dist/editor/encode.d.ts +7 -0
  22. package/dist/editor/index.d.ts +5 -0
  23. package/dist/editor/mask.d.ts +29 -0
  24. package/dist/editor/pii.d.ts +22 -0
  25. package/dist/editor/shapes.d.ts +31 -0
  26. package/dist/editor-loader.d.ts +9 -0
  27. package/dist/editor-loader.embed.d.ts +6 -0
  28. package/dist/fixcheck.d.ts +42 -0
  29. package/dist/index.d.ts +85 -0
  30. package/dist/known.d.ts +27 -0
  31. package/dist/mount.d.ts +8 -0
  32. package/dist/navigation.d.ts +1 -0
  33. package/dist/paths.d.ts +4 -0
  34. package/dist/pinax-axe.js +46167 -0
  35. package/dist/pinax-editor.js +1417 -0
  36. package/dist/pinax-recorder.js +2915 -0
  37. package/dist/pinax.js +135 -0
  38. package/dist/pinax.mjs +1270 -0
  39. package/dist/preview.d.ts +48 -0
  40. package/dist/preview.mjs +67 -0
  41. package/dist/privacy.d.ts +24 -0
  42. package/dist/queue.d.ts +10 -0
  43. package/dist/replay/buffer.d.ts +40 -0
  44. package/dist/replay/recorder.d.ts +25 -0
  45. package/dist/replay/sanitize.d.ts +19 -0
  46. package/dist/report.d.ts +128 -0
  47. package/dist/segment.d.ts +31 -0
  48. package/dist/settings.d.ts +40 -0
  49. package/dist/types.d.ts +247 -0
  50. package/dist/ui/color.d.ts +7 -0
  51. package/dist/ui/dom.d.ts +14 -0
  52. package/dist/ui/styles.d.ts +3 -0
  53. package/dist/ui/widget.d.ts +241 -0
  54. package/package.json +74 -4
@@ -0,0 +1,247 @@
1
+ export type PinaxOptions = {
2
+ /** The website's public key (S-08). */
3
+ key: string;
4
+ /** Override the API origin, e.g. for local development. */
5
+ apiUrl?: string;
6
+ /** Segment: force sending events to `window.analytics` on or off, whatever the site's setting. */
7
+ segment?: boolean;
8
+ /**
9
+ * Override the CDN origin that serves the site's settings (P-15), default
10
+ * https://cdn.getpinax.com. When `apiUrl` is set and this isn't, settings
11
+ * come from the API.
12
+ */
13
+ cdnUrl?: string;
14
+ /**
15
+ * Visitor consent: `'wait'` holds replay, technical logs, error counts
16
+ * and the page-view count until `consent()` says yes; `'none'` never
17
+ * waits. Without it the site's setting (`settings.consent.required`)
18
+ * decides. `data-consent` on the script tag.
19
+ */
20
+ consent?: 'wait' | 'none';
21
+ };
22
+ /**
23
+ * Visitor consent, from the site's cookie banner: `true` or `false` for
24
+ * everything, or only the parts given. `diagnostics` covers technical logs
25
+ * on reports, fix checks, error counts (with the basket), the Segment user id
26
+ * and the page-view count; `replay` the session recorder.
27
+ */
28
+ export type PinaxConsent = boolean | {
29
+ diagnostics?: boolean;
30
+ replay?: boolean;
31
+ };
32
+ /**
33
+ * Signed-in visitor details (C-09). `id` and `name` go with reports; `email`
34
+ * only fills in the form's email box (when the site allows it) and is sent
35
+ * only if the visitor leaves it there.
36
+ */
37
+ export type PinaxUser = {
38
+ id?: string;
39
+ name?: string;
40
+ email?: string;
41
+ };
42
+ /**
43
+ * AI-21: what the visitor has in their basket right now, in major units
44
+ * (19.99, not 1999) and an ISO 4217 code. Sent only with a sampled
45
+ * sighting of an open report's error (P-17), never on its own.
46
+ */
47
+ export type PinaxBasket = {
48
+ value: number;
49
+ currency: string;
50
+ };
51
+ export type WidgetPosition = 'bottom-right' | 'bottom-left' | 'right-edge';
52
+ /** S-06: custom wording. An empty string means "use the default wording". */
53
+ export type WidgetWording = {
54
+ chooserTitle: string;
55
+ problemTitle: string;
56
+ ideaTitle: string;
57
+ generalTitle: string;
58
+ /** W-19 */
59
+ accessibilityTitle: string;
60
+ messagePlaceholder: string;
61
+ confirmation: string;
62
+ };
63
+ /** W-10: an owner-defined field in the form. */
64
+ export type CustomField = {
65
+ id: string;
66
+ type: 'select' | 'text' | 'checkbox';
67
+ label: string;
68
+ required: boolean;
69
+ /** Dropdown choices. */
70
+ options: string[];
71
+ /** Which kinds of feedback show it. */
72
+ types: {
73
+ problem: boolean;
74
+ idea: boolean;
75
+ general: boolean;
76
+ };
77
+ };
78
+ /** W-10: a visitor's answer, as sent in the report body. */
79
+ export type FieldAnswer = {
80
+ id: string;
81
+ value: string | boolean;
82
+ };
83
+ /**
84
+ * The website's widget settings, as defined by
85
+ * `backend/src/modules/widget/widget-settings.ts`.
86
+ */
87
+ export type WidgetSettings = {
88
+ /** S-01 */
89
+ color: string;
90
+ text: string;
91
+ position: WidgetPosition;
92
+ /** S-02; W-19 `accessibility` is off unless the owner switches it on. */
93
+ types: {
94
+ problem: boolean;
95
+ idea: boolean;
96
+ general: boolean;
97
+ accessibility: boolean;
98
+ };
99
+ rating: boolean;
100
+ /** S-04: path patterns where the button is hidden; `*` matches anything. */
101
+ hidePaths: string[];
102
+ /** S-04: a smaller button on phones. */
103
+ smallOnMobile: boolean;
104
+ /** S-05: no floating button; the site opens the widget with `Pinax.open()`. */
105
+ hideButton: boolean;
106
+ /** Segment: send widget events to the page's own `window.analytics`. */
107
+ segment: boolean;
108
+ /** S-06 */
109
+ wording: WidgetWording;
110
+ /** W-10 */
111
+ fields: CustomField[];
112
+ /** C-10: what is recorded with each report. */
113
+ capture: {
114
+ console: boolean;
115
+ network: boolean;
116
+ };
117
+ /**
118
+ * Known issues: show the "We know about this" card, and offer "Email me
119
+ * when it's fixed". Missing (older API) means both on, as the backend's
120
+ * defaults; with no `known` list in the config there's nothing to show.
121
+ */
122
+ knownIssues?: {
123
+ enabled: boolean;
124
+ notify: boolean;
125
+ };
126
+ /**
127
+ * Visitor consent: the site has a cookie banner, so replay, technical
128
+ * logs, error counts and the page-view count wait for `Pinax.consent()`.
129
+ * Missing (older API) means not required.
130
+ */
131
+ consent?: {
132
+ required: boolean;
133
+ };
134
+ /** The site's privacy policy (https), linked under the form; `''` = none. */
135
+ privacyUrl?: string;
136
+ /**
137
+ * Whether `identify()`'s email fills in the form's email box (the visitor
138
+ * can clear it). Missing (older API) means yes, as before.
139
+ */
140
+ identifyPrefill?: boolean;
141
+ };
142
+ /**
143
+ * W-17: "Powered by Pinax" (Starter) and, with client branding (Agency),
144
+ * the client's logo and colours. Missing or null = Pinax's own look.
145
+ */
146
+ export type Branding = {
147
+ poweredBy: boolean;
148
+ logoUrl?: string | null;
149
+ primary?: string | null;
150
+ accent?: string | null;
151
+ };
152
+ /** AI-17: a report marked Fixed whose error the widget watches for. */
153
+ export type FixCheck = {
154
+ id: string;
155
+ path: string;
156
+ signature: string;
157
+ };
158
+ /** AI-20: an open report whose error the widget counts on any page. */
159
+ export type ErrorWatch = {
160
+ id: string;
161
+ signature: string;
162
+ };
163
+ /**
164
+ * Pinax AI switches for the browser (`widgetAiConfig` in
165
+ * `backend/src/modules/widget/widget.service.ts`).
166
+ */
167
+ export type AiConfig = {
168
+ /** AI-10: ask one follow-up question about a short note. */
169
+ followUp: boolean;
170
+ /** AI-12: blur emails, phone numbers and names in screenshots. */
171
+ autoBlur: boolean;
172
+ /** AI-15 / P-13: keep a rolling 30-second replay (Pro and Agency). */
173
+ replay: boolean;
174
+ replaySampleRate: number;
175
+ /**
176
+ * What the recorder hides: `'all'` (the default) every text and every
177
+ * image, video, canvas and frame; `'inputs'` form fields, editable text,
178
+ * emails and phone numbers.
179
+ */
180
+ replayMask: 'all' | 'inputs';
181
+ /** AI-17 / P-14 */
182
+ fixChecks: FixCheck[];
183
+ /** AI-20 / P-17: open reports' errors, counted when seen; same sample rate as fix checks. */
184
+ watches: ErrorWatch[];
185
+ fixCheckSampleRate: number;
186
+ };
187
+ /**
188
+ * An open report the team chose to show to visitors, with a public title
189
+ * they wrote (never the visitor's own words).
190
+ */
191
+ export type KnownIssue = {
192
+ id: string;
193
+ title: string;
194
+ /** Pages it was reported on; `/a` and `/a/` are the same page. */
195
+ paths: string[];
196
+ /** Its error signature (`errorSignature`), when it has one. */
197
+ signature: string | null;
198
+ };
199
+ /** `data` of GET /v1/widget/:key/config. */
200
+ export type WidgetConfig = {
201
+ enabled: boolean;
202
+ /** S-15: hostnames that may send reports. Missing (older API) means don't check. */
203
+ allowedDomains?: string[];
204
+ settings: WidgetSettings;
205
+ branding: Branding;
206
+ /** B-17: over the limit, replay and fix-check sampling is cut (to 0.01). */
207
+ samplingRate?: number | null;
208
+ ai?: AiConfig;
209
+ /** Known issues for this site (up to 20). Missing (older API) means none. */
210
+ known?: KnownIssue[];
211
+ };
212
+ export type ReportType = 'PROBLEM' | 'IDEA' | 'GENERAL' | 'ACCESSIBILITY';
213
+ /** W-19: what kind of barrier the visitor met (optional). */
214
+ export type Barrier = 'see' | 'keyboard' | 'screen-reader' | 'media' | 'other';
215
+ /** W-20: one failed axe-core rule. */
216
+ export type A11yIssue = {
217
+ rule: string;
218
+ impact: 'minor' | 'moderate' | 'serious' | 'critical' | null;
219
+ help: string;
220
+ helpUrl: string;
221
+ /** WCAG success criteria, e.g. "1.4.3". */
222
+ wcag: string[];
223
+ /** How many elements fail it; `nodes` holds the first few. */
224
+ count: number;
225
+ nodes: {
226
+ target: string;
227
+ html: string;
228
+ summary: string;
229
+ }[];
230
+ };
231
+ /** W-20: the automatic scan sent with an accessibility report. */
232
+ export type A11yScan = {
233
+ engine: string;
234
+ durationMs: number;
235
+ violations: A11yIssue[];
236
+ /** Rules that needed a person to check (not failures). */
237
+ incomplete: number;
238
+ };
239
+ /** One drawn mark, coordinates as fractions (0 to 1) of the sent image. */
240
+ export type Annotation = {
241
+ type: 'box' | 'arrow' | 'text' | 'blur';
242
+ x: number;
243
+ y: number;
244
+ w: number;
245
+ h: number;
246
+ text?: string;
247
+ };
@@ -0,0 +1,7 @@
1
+ /** Relative luminance of a #rgb or #rrggbb colour (WCAG 2). */
2
+ export declare function luminance(hex: string): number | null;
3
+ export declare function contrast(a: number, b: number): number;
4
+ /** The board's dark ink (#0B1300) or white, whichever reads better on `bg`. */
5
+ export declare function inkFor(bg: string): string;
6
+ /** Only accept plain hex colours from config, so nothing odd reaches CSS. */
7
+ export declare function safeColor(value: unknown, fallback?: string): string;
@@ -0,0 +1,14 @@
1
+ type Attrs = Record<string, string | number | boolean | undefined | null>;
2
+ type Child = Node | string | null | undefined | false;
3
+ /** Tiny element builder. Text is always set as text, never parsed as HTML. */
4
+ export declare function h<K extends keyof HTMLElementTagNameMap>(tag: K, attrs?: Attrs, ...children: Child[]): HTMLElementTagNameMap[K];
5
+ /** A 16px stroked icon from a path. */
6
+ export declare function icon(d: string, size?: number): SVGSVGElement;
7
+ export declare const ICONS: {
8
+ close: string;
9
+ back: string;
10
+ pen: string;
11
+ camera: string;
12
+ trash: string;
13
+ };
14
+ export {};
@@ -0,0 +1,3 @@
1
+ /** The phone rules inside `open` (a media query or ''), `$` replaced by `wrap`. */
2
+ export declare function phoneRules(open: string, wrap: string): string;
3
+ export declare const CSS: string;
@@ -0,0 +1,241 @@
1
+ import type { Annotation, Barrier, FieldAnswer, KnownIssue, PinaxUser, ReportType, WidgetConfig } from '../types';
2
+ export type Shot = {
3
+ /** The flattened image that will be sent. */
4
+ dataUrl: string;
5
+ annotations: Annotation[];
6
+ /** Opaque editor state so "Mark up" can continue where it left off. */
7
+ edit?: unknown;
8
+ /** AI-12: how many private details were blurred automatically. */
9
+ autoBlurred?: number;
10
+ };
11
+ export type SubmitInput = {
12
+ type: ReportType;
13
+ message: string;
14
+ rating?: number;
15
+ email?: string;
16
+ shot?: Shot;
17
+ /** AI-10: the follow-up question and the visitor's answer. */
18
+ followUp?: {
19
+ question: string;
20
+ answer: string;
21
+ };
22
+ /** W-10: answers to the site's custom fields. */
23
+ fields?: FieldAnswer[];
24
+ /** W-19: the kind of accessibility barrier, when the visitor chose one. */
25
+ barrier?: Barrier;
26
+ /** P-04: the hidden honeypot field (people leave it empty). */
27
+ hp?: string;
28
+ /** P-04: milliseconds from opening the panel to sending. */
29
+ elapsedMs?: number;
30
+ /** Visitor consent: the visitor ticked "Include technical details". */
31
+ includeLogs?: boolean;
32
+ /** What the notice above Send said would go; nothing else is attached. */
33
+ listed?: {
34
+ logs: boolean;
35
+ replay: boolean;
36
+ };
37
+ };
38
+ /**
39
+ * Visitor consent: what goes with a report besides the note, for the
40
+ * notice above Send. `logs`: technical logs go as things stand; `askLogs`:
41
+ * they go only if the visitor ticks the box (shown then); `replay`: the
42
+ * last 30 seconds go.
43
+ */
44
+ export type Attachments = {
45
+ logs: boolean;
46
+ askLogs: boolean;
47
+ replay: boolean;
48
+ };
49
+ /** AI-10: only short notes on problems and ideas get a follow-up question. */
50
+ export declare const FOLLOW_UP_MAX_NOTE = 140;
51
+ export type SubmitResult = {
52
+ status: 'sent';
53
+ } | {
54
+ status: 'queued';
55
+ } | {
56
+ status: 'error';
57
+ message: string;
58
+ };
59
+ export type UIHandlers = {
60
+ takeScreenshot(): Promise<Shot>;
61
+ markUp(shot: Shot): Promise<Shot | null>;
62
+ submit(input: SubmitInput): Promise<SubmitResult>;
63
+ user(): PinaxUser | undefined;
64
+ /** Called each time the panel opens (Segment). Must not throw. */
65
+ opened?(): void;
66
+ /**
67
+ * AI-10: one follow-up question for a short note, or null to send as is.
68
+ * Must resolve (to null) on errors and within a few seconds.
69
+ */
70
+ followUp?(input: {
71
+ type: ReportType;
72
+ message: string;
73
+ }): Promise<string | null>;
74
+ /** Known issues that match this page view, asked each time the panel opens. */
75
+ knownIssues?(): KnownIssue[];
76
+ /** Known issues: "Me too", with an email when given. False on any error. */
77
+ meToo?(id: string, email?: string): Promise<boolean>;
78
+ /**
79
+ * Visitor consent: what a report would carry now (see `Attachments`).
80
+ * Without it: technical logs, no box, no recording.
81
+ */
82
+ attachments?(): Attachments;
83
+ /** Who the report goes to, in the notice. Default: this page's host name. */
84
+ site?(): string;
85
+ };
86
+ /** A screen of the panel, or 'button' for the closed widget. */
87
+ export type WidgetView = 'button' | 'choose' | 'problem' | 'idea' | 'general' | 'accessibility' | 'done';
88
+ /**
89
+ * The floating button and the feedback panel (W-01, W-02, W-07 to W-11,
90
+ * W-15). Everything renders inside the shadow root.
91
+ */
92
+ export declare class WidgetUI {
93
+ private root;
94
+ private config;
95
+ private handlers;
96
+ private wrap;
97
+ private launcher;
98
+ private panel;
99
+ private live;
100
+ private kinds;
101
+ private kind;
102
+ private shot;
103
+ private message;
104
+ private email;
105
+ /** The visitor typed in, changed or cleared an email box: never refill it. */
106
+ private emailEdited;
107
+ private rating;
108
+ /** W-19 */
109
+ private barrier;
110
+ /** W-10: answers by field id. */
111
+ private answers;
112
+ /** W-17: the client's colour on Send buttons (Agency). */
113
+ private sendColour;
114
+ private sending;
115
+ /** P-04: when the panel opened, and the honeypot field's value. */
116
+ private openedAt;
117
+ private hp;
118
+ private closeTimer;
119
+ private uid;
120
+ /** S-04 hidden path, set from outside as the visitor navigates. */
121
+ private pathHidden;
122
+ /** Where focus goes back to on close when there's no button to return to. */
123
+ private returnFocus;
124
+ /** Known issues matched when the panel last opened, and those the visitor moved past. */
125
+ private known;
126
+ private knownHidden;
127
+ private meToo;
128
+ /** Visitor consent: the "Include technical details" box, unticked to start. */
129
+ private includeLogs;
130
+ /** The notice above Send on show, and what it said would go. */
131
+ private privacy;
132
+ private noticeText;
133
+ private shown;
134
+ constructor(root: ShadowRoot, config: WidgetConfig, handlers: UIHandlers,
135
+ /** Extra classes on the wrapper and extra CSS (the dashboard preview). */
136
+ extra?: {
137
+ className?: string;
138
+ css?: string;
139
+ });
140
+ isOpen(): boolean;
141
+ /** True while the floating button is on screen (S-04, S-05). */
142
+ hasButton(): boolean;
143
+ /**
144
+ * S-04: hide or show the floating button for the current page. An open
145
+ * panel stays open, and `open()` keeps working either way.
146
+ */
147
+ setPathHidden(hidden: boolean): void;
148
+ private updateButton;
149
+ /** `focus: false` opens without moving focus (the dashboard preview). */
150
+ open(focus?: boolean): void;
151
+ close(restoreFocus?: boolean): void;
152
+ /** The screen on show, for the dashboard preview. */
153
+ currentView(): WidgetView;
154
+ /**
155
+ * Dashboard preview: jump straight to a screen without moving focus. A
156
+ * type that's switched off shows the chooser instead.
157
+ */
158
+ showView(view: WidgetView): void;
159
+ /** S-06: the owner's wording, or ours when they left it empty. */
160
+ private word;
161
+ private kindTitle;
162
+ /** Hides the panel while the full-screen editor is up. */
163
+ private setSuspended;
164
+ destroy(): void;
165
+ private view;
166
+ private queued;
167
+ /** AI-10: the question asked about `message`, and the answer so far. */
168
+ private asked;
169
+ private answer;
170
+ private reset;
171
+ private holdOpen;
172
+ private focusFirst;
173
+ private announce;
174
+ private pick;
175
+ private capture;
176
+ private markUp;
177
+ private renderKeepingFocus;
178
+ private header;
179
+ private powered;
180
+ /** W-17: the client's logo at the top of the panel (Agency). */
181
+ private logo;
182
+ private render;
183
+ private renderChoose;
184
+ /** Known issues: the matches on show, without those the visitor moved past. */
185
+ private knownShown;
186
+ /** Asks which known issues match now; with any, the panel starts on the card. */
187
+ private offerKnown;
188
+ /**
189
+ * Known issues: "We know about this", each issue's public title and a
190
+ * Me too button; after it, thanks and (when the site allows it) "Email me
191
+ * when it's fixed". "Report something else" leaves the card.
192
+ */
193
+ private renderKnown;
194
+ /** Me too, or (with `emailEl`) the email to hear when it's fixed. */
195
+ private sendMeToo;
196
+ private renderShot;
197
+ private renderStars;
198
+ private renderForm;
199
+ /** The optional email, the honeypot, the error line and Send. */
200
+ private renderEmailAndSend;
201
+ /** Visitor consent: what a report would carry now. */
202
+ private attachments;
203
+ /**
204
+ * Above Send: the "Include technical details" box (only while the page
205
+ * waits for consent and the visitor hasn't given it), then what goes
206
+ * with the note, and the site's privacy policy.
207
+ */
208
+ private renderPrivacy;
209
+ /** "Sent to … with your note: …", listing only what will go. */
210
+ private updateNotice;
211
+ /**
212
+ * Consent changed, or the recorder started: the notice (and the box)
213
+ * above Send follow, in place, so typing and focus aren't disturbed.
214
+ */
215
+ refresh(): void;
216
+ /**
217
+ * W-19: a short form that works well with a screen reader and the
218
+ * keyboard alone: native radio buttons, real labels, no screenshot unless
219
+ * the visitor adds one, and a note saying who reads it.
220
+ */
221
+ private renderAccessibility;
222
+ /**
223
+ * P-04: a field people never see or reach (off-screen, out of the tab
224
+ * order and hidden from screen readers). Form-filling bots fill it in.
225
+ */
226
+ private honeypot;
227
+ private send;
228
+ /** The follow-up question for this note, or null (no question, error, timeout). */
229
+ private askFollowUp;
230
+ private submitNow;
231
+ /** AI-10: one question about the note, with "Send" and "Skip and send". */
232
+ private renderQuestion;
233
+ /** W-17: the client's colour on Send, else the colour of the kind. */
234
+ private colourSend;
235
+ /** W-10: the owner's fields for this kind of feedback. */
236
+ private fieldsFor;
237
+ private fieldAnswers;
238
+ /** W-10: dropdowns, short text and checkboxes, labelled and keyboard friendly. */
239
+ private renderFields;
240
+ private renderDone;
241
+ }
package/package.json CHANGED
@@ -1,6 +1,76 @@
1
1
  {
2
2
  "name": "@getpinax/widget",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.0-beta.2",
4
+ "type": "module",
5
+ "description": "Pinax website feedback widget: a feedback button with screenshots, markup and page context",
6
+ "license": "MIT",
7
+ "author": "Pinax <hello@getpinax.com>",
8
+ "homepage": "https://getpinax.com",
9
+ "bugs": {
10
+ "email": "hello@getpinax.com"
11
+ },
12
+ "keywords": [
13
+ "feedback",
14
+ "bug-report",
15
+ "widget",
16
+ "screenshot",
17
+ "pinax"
18
+ ],
19
+ "sideEffects": false,
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "main": "./dist/pinax.mjs",
24
+ "module": "./dist/pinax.mjs",
25
+ "types": "./dist/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "import": "./dist/pinax.mjs"
30
+ },
31
+ "./preview": {
32
+ "types": "./dist/preview.d.ts",
33
+ "import": "./dist/preview.mjs"
34
+ },
35
+ "./package.json": "./package.json"
36
+ },
37
+ "files": [
38
+ "dist",
39
+ "!dist/**/*.map",
40
+ "README.md",
41
+ "LICENSE"
42
+ ],
43
+ "scripts": {
44
+ "dev": "vite",
45
+ "build": "tsc --noEmit && vite build && vite build --mode editor && vite build --mode recorder && vite build --mode axe && vite build --mode embed && tsc -p tsconfig.build.json && node scripts/check-size.mjs",
46
+ "test": "vitest run",
47
+ "typecheck": "tsc --noEmit",
48
+ "check": "biome check ./src ./cdn",
49
+ "check:fix": "biome check --write ./src ./cdn",
50
+ "size": "node scripts/check-size.mjs",
51
+ "playground": "yarn build && node scripts/serve-playground.mjs",
52
+ "prepublishOnly": "VITE_PINAX_API=https://api.getpinax.com VITE_PINAX_CDN=https://cdn.getpinax.com yarn build && yarn test",
53
+ "cdn:deploy": "./cdn/deploy.sh",
54
+ "release": "bash scripts/release.sh"
55
+ },
56
+ "devDependencies": {
57
+ "@biomejs/biome": "^2.6.5",
58
+ "@types/node": "^22",
59
+ "jsdom": "^30.1.3",
60
+ "typescript": "^7.0.2",
61
+ "vite": "^8.3.5",
62
+ "vitest": "^5.1.0"
63
+ },
64
+ "dependencies": {
65
+ "@rrweb/record": "2.1.7",
66
+ "axe-core": "^4.10.0",
67
+ "modern-screenshot": "^4.7.0"
68
+ },
69
+ "resolutions": {
70
+ "rrweb": "2.1.7",
71
+ "rrweb-snapshot": "2.1.7",
72
+ "rrdom": "2.1.7",
73
+ "@rrweb/types": "2.1.7",
74
+ "@rrweb/utils": "2.1.7"
75
+ }
76
+ }