@journeeze/sdk 0.0.0-stage → 0.1.0-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +80 -0
- package/CHANGELOG.md +41 -0
- package/LICENSE.md +27 -0
- package/README.md +343 -2
- package/dist/THIRD_PARTY_LICENSES.txt +246 -0
- package/dist/anchor-cPvFFTOS.js +1 -0
- package/dist/attach-DpioALxW.js +21 -0
- package/dist/chat-BgmB0rnW.js +64 -0
- package/dist/consent-DckCUvYR.js +1 -0
- package/dist/context-UnG6_X61.js +17 -0
- package/dist/contract.js +10 -0
- package/dist/feedback-CtH1a_kQ.js +1 -0
- package/dist/help-w0O5Qu-4.js +105 -0
- package/dist/hook-DGWypoEO.js +1 -0
- package/dist/index-B_nob8S0.js +1 -0
- package/dist/index-CwG2LrhO.js +20 -0
- package/dist/index.js +10 -0
- package/dist/jobs-CAXbM5-g.js +45 -0
- package/dist/loader-BZiIDD1D.js +96 -0
- package/dist/mask-audit-Du3NPoG_.js +5 -0
- package/dist/react.js +71 -0
- package/dist/resolve-BfWByuTp.js +1 -0
- package/dist/script.js +14 -0
- package/dist/signals-amjMQyOy.js +1 -0
- package/dist/telemetry-CyRJDaVs.js +1 -0
- package/dist/transport-B64CfIcF.js +1 -0
- package/dist/types/chat/capture/attach.d.ts +41 -0
- package/dist/types/chat/capture/draw.d.ts +10 -0
- package/dist/types/chat/capture/geometry.d.ts +30 -0
- package/dist/types/chat/capture/styles.d.ts +1 -0
- package/dist/types/chat/shell/chat.d.ts +27 -0
- package/dist/types/chat/shell/converse.d.ts +95 -0
- package/dist/types/chat/shell/copy.d.ts +8 -0
- package/dist/types/chat/shell/model.d.ts +36 -0
- package/dist/types/chat/shell/session.d.ts +148 -0
- package/dist/types/chat/shell/styles.d.ts +1 -0
- package/dist/types/chat/shell/view.d.ts +18 -0
- package/dist/types/chat/transport.d.ts +5 -0
- package/dist/types/config.d.ts +34 -0
- package/dist/types/context.d.ts +6 -0
- package/dist/types/contract.d.ts +13 -0
- package/dist/types/help/core/client.d.ts +26 -0
- package/dist/types/help/core/controller.d.ts +184 -0
- package/dist/types/help/core/events.d.ts +32 -0
- package/dist/types/help/core/help.d.ts +25 -0
- package/dist/types/help/core/highlight.d.ts +38 -0
- package/dist/types/help/core/panel.d.ts +27 -0
- package/dist/types/help/core/routing.d.ts +21 -0
- package/dist/types/help/core/search.d.ts +7 -0
- package/dist/types/help/ui/callout.d.ts +2 -0
- package/dist/types/help/ui/jobs/jobs.d.ts +24 -0
- package/dist/types/help/ui/jobs/model.d.ts +33 -0
- package/dist/types/help/ui/jobs/styles.d.ts +1 -0
- package/dist/types/help/ui/panel.d.ts +3 -0
- package/dist/types/help/ui/request.d.ts +2 -0
- package/dist/types/help/ui/styles.d.ts +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/invite.d.ts +4 -0
- package/dist/types/loader.d.ts +59 -0
- package/dist/types/mask-detector.d.ts +22 -0
- package/dist/types/mask.d.ts +10 -0
- package/dist/types/preview/flag.d.ts +2 -0
- package/dist/types/preview/mask-audit.d.ts +29 -0
- package/dist/types/react.d.ts +9 -0
- package/dist/types/resolve/resolve.d.ts +12 -0
- package/dist/types/schemas/feedback.d.ts +76 -0
- package/dist/types/schemas/finding.d.ts +22 -0
- package/dist/types/schemas/index.d.ts +6 -0
- package/dist/types/schemas/turn.d.ts +26 -0
- package/dist/types/script.d.ts +6 -0
- package/dist/types/signals/cel.d.ts +8 -0
- package/dist/types/signals/hook.d.ts +10 -0
- package/dist/types/signals/signals.d.ts +149 -0
- package/dist/types/signals/steps.d.ts +33 -0
- package/dist/types/telemetry/telemetry.d.ts +73 -0
- package/dist/types/transport.d.ts +30 -0
- package/dist/types/types.d.ts +462 -0
- package/dist/types/widget/anchor.d.ts +11 -0
- package/dist/types/widget/capture.d.ts +39 -0
- package/dist/types/widget/consent.d.ts +25 -0
- package/dist/types/widget/feedback.d.ts +36 -0
- package/dist/types/widget/icons.d.ts +14 -0
- package/dist/types/widget/outbox.d.ts +69 -0
- package/dist/types/widget/styles.d.ts +1 -0
- package/dist/types/widget/upload.d.ts +14 -0
- package/dist/types/widget.d.ts +7 -0
- package/dist/types/wire.d.ts +66 -0
- package/dist/upload-Fu2qvSJV.js +14 -0
- package/dist/widget-B6mR1J3P.js +118 -0
- package/package.json +70 -4
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { MountOptions } from "../loader";
|
|
2
|
+
import type { GetWidgetConfigResponse, JourneezeOptions } from "../types";
|
|
3
|
+
import { CollectorError } from "../wire";
|
|
4
|
+
import { Outbox } from "./outbox";
|
|
5
|
+
export interface FeedbackChannel {
|
|
6
|
+
readonly outbox: Outbox;
|
|
7
|
+
/** Removes the page listeners and stores what is unsent for a later widget or help. */
|
|
8
|
+
dispose(): void;
|
|
9
|
+
}
|
|
10
|
+
export interface FeedbackChannelHooks {
|
|
11
|
+
/** Runs on pagehide before the outbox is persisted (the widget stashes pending uploads). */
|
|
12
|
+
beforePersist?: () => void;
|
|
13
|
+
onDropped?: (error: CollectorError) => void;
|
|
14
|
+
/**
|
|
15
|
+
* Keep unsent items in memory only, never in browser storage: an anonymous reader of public
|
|
16
|
+
* help (ADR 0013 §3). Unsent items are then lost when the page goes away.
|
|
17
|
+
*/
|
|
18
|
+
memoryOnly?: boolean;
|
|
19
|
+
}
|
|
20
|
+
type ChannelOptions = JourneezeOptions & Partial<Pick<MountOptions, "userId" | "pagePath" | "apiHost" | "apiPath">>;
|
|
21
|
+
/**
|
|
22
|
+
* Whose outbox items these are (contract §9, v1.1): the reviewer token on reviewer sites, else the
|
|
23
|
+
* signed-in user, else anonymous. A page claims only its own owner's items.
|
|
24
|
+
*/
|
|
25
|
+
export declare const ownerOf: (o: ChannelOptions) => string;
|
|
26
|
+
/**
|
|
27
|
+
* The storage half of `reset()` (contract §8, v1.1), loaded only at logout: this owner's stored
|
|
28
|
+
* feedback is removed from the device now and sent once (keepalive within the page-end budget,
|
|
29
|
+
* else plain fetch); a send that fails is lost, by design, so no comment text of the user stays at
|
|
30
|
+
* rest on a shared device. The anonymous consent is forgotten (the loader clears the reviewer token).
|
|
31
|
+
*/
|
|
32
|
+
export declare function logout(options: ChannelOptions): Promise<void>;
|
|
33
|
+
export declare function feedbackChannel(options: ChannelOptions, endpoint: string, hooks?: FeedbackChannelHooks): FeedbackChannel;
|
|
34
|
+
/** The site's public widget configuration (consent copy, personas). */
|
|
35
|
+
export declare function widgetConfig(endpoint: string, siteKey: string): Promise<GetWidgetConfigResponse>;
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
declare const PATHS: {
|
|
2
|
+
readonly like: "<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M8 14s1.5 2 4 2 4-2 4-2\"/><path d=\"M9 9h.01\"/><path d=\"M15 9h.01\"/>";
|
|
3
|
+
readonly dislike: "<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M16 16s-1.5-2-4-2-4 2-4 2\"/><path d=\"M9 9h.01\"/><path d=\"M15 9h.01\"/>";
|
|
4
|
+
readonly understood: "<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"m9 12 2 2 4-4\"/>";
|
|
5
|
+
readonly confused: "<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3\"/><path d=\"M12 17h.01\"/>";
|
|
6
|
+
readonly close: "<path d=\"M18 6 6 18\"/><path d=\"m6 6 12 12\"/>";
|
|
7
|
+
readonly persona: "<path d=\"M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2\"/><circle cx=\"12\" cy=\"7\" r=\"4\"/>";
|
|
8
|
+
readonly step: "<path d=\"M5 12h14\"/><path d=\"m12 5 7 7-7 7\"/>";
|
|
9
|
+
readonly info: "<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M12 16v-4\"/><path d=\"M12 8h.01\"/>";
|
|
10
|
+
};
|
|
11
|
+
export type IconName = keyof typeof PATHS;
|
|
12
|
+
/** A decorative (aria-hidden) inline SVG icon. Static markup only. */
|
|
13
|
+
export declare function icon(name: IconName, size?: number): SVGSVGElement;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { CollectorError } from "../wire";
|
|
2
|
+
import type { SubmitFeedbackRequest } from "../types";
|
|
3
|
+
/** Stored feedback older than this is stale and is dropped when claimed (§9). */
|
|
4
|
+
export declare const OUTBOX_TTL_MS: number;
|
|
5
|
+
export type Outcome = "sent" | "queued" | "dropped";
|
|
6
|
+
export interface OutboxDeps {
|
|
7
|
+
send(request: SubmitFeedbackRequest): Promise<void>;
|
|
8
|
+
storage: Storage | undefined;
|
|
9
|
+
storageKey: string;
|
|
10
|
+
/** Which reviewer queued the items ({@link ownerTag}); only matching items are claimed. */
|
|
11
|
+
owner: string;
|
|
12
|
+
/** Scheduling seam for tests. */
|
|
13
|
+
schedule?: (fn: () => void, ms: number) => unknown;
|
|
14
|
+
cancel?: (handle: unknown) => void;
|
|
15
|
+
/** Called when an item is dropped as permanently refused. */
|
|
16
|
+
onDropped?: (error: CollectorError) => void;
|
|
17
|
+
/** The signed-in user (opaque id) an item is stored under, kept with it for attribution (J6). */
|
|
18
|
+
user?: () => string | undefined;
|
|
19
|
+
/** Clock seam for tests; defaults to `Date.now`. */
|
|
20
|
+
now?: () => number;
|
|
21
|
+
}
|
|
22
|
+
export declare function backoffMs(attempt: number): number;
|
|
23
|
+
export declare function isPermanent(error: unknown): error is CollectorError;
|
|
24
|
+
export declare class Outbox {
|
|
25
|
+
private readonly deps;
|
|
26
|
+
private items;
|
|
27
|
+
private inFlight;
|
|
28
|
+
private attempt;
|
|
29
|
+
private flushing;
|
|
30
|
+
private timer;
|
|
31
|
+
private disposed;
|
|
32
|
+
private readonly schedule;
|
|
33
|
+
private readonly cancel;
|
|
34
|
+
private readonly now;
|
|
35
|
+
constructor(deps: OutboxDeps);
|
|
36
|
+
get size(): number;
|
|
37
|
+
/** Queues and flushes; resolves once this item was sent, dropped, or left queued for retry. */
|
|
38
|
+
enqueue(request: SubmitFeedbackRequest): Promise<Outcome>;
|
|
39
|
+
/** Queues without sending (used while the page is being hidden). */
|
|
40
|
+
stash(request: SubmitFeedbackRequest): void;
|
|
41
|
+
/** Sends queued items in order. One flush at a time; a pending retry timer is replaced. */
|
|
42
|
+
flush(): Promise<void>;
|
|
43
|
+
/** Hands unsent items to storage (appending to what is there) and forgets them here. */
|
|
44
|
+
persist(): void;
|
|
45
|
+
/** Takes over this reviewer's items stored by earlier pages (this or another tab). Items of
|
|
46
|
+
* another reviewer stay stored: they are never sent under the wrong reviewer's token. */
|
|
47
|
+
claim(): void;
|
|
48
|
+
/** Stops sending and stores what is unsent so a later widget can deliver it. */
|
|
49
|
+
dispose(): void;
|
|
50
|
+
private add;
|
|
51
|
+
private drain;
|
|
52
|
+
/**
|
|
53
|
+
* Stored items older than {@link OUTBOX_TTL_MS} are dropped (contract §9). An item without a
|
|
54
|
+
* time was queued by a v0 SDK before the upgrade: it is sent once rather than lost.
|
|
55
|
+
*/
|
|
56
|
+
private fresh;
|
|
57
|
+
private remove;
|
|
58
|
+
private read;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Non-reversible tag of the reviewer token (FNV-1a, 32 bits) so stored items are claimed only
|
|
62
|
+
* by the same reviewer. 32 bits of a 256-bit token reveal nothing usable; "" means anonymous.
|
|
63
|
+
*/
|
|
64
|
+
export declare function ownerTag(token: string | undefined): string;
|
|
65
|
+
/**
|
|
66
|
+
* Logout (contract §8, v1.1): removes this owner's stored items from storage now, whatever happens
|
|
67
|
+
* next, and returns their requests (those still within {@link OUTBOX_TTL_MS}) to be sent once.
|
|
68
|
+
*/
|
|
69
|
+
export declare function takeOwned(storage: Storage | undefined, storageKey: string, owner: string, now?: number): SubmitFeedbackRequest[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const CSS = "\n:host { all: initial; }\n.jz {\n --jz-canvas:#F7F7F5; --jz-surface:#FFFFFF; --jz-raised:#F0F0EC; --jz-ink:#1D2024; --jz-muted:#5D636B;\n --jz-faint:#8A9099; --jz-rule:rgb(29 32 36 / 12%); --jz-accent:#3D63C9; --jz-accent-ink:#FFFFFF;\n --jz-accent-soft:rgb(61 99 201 / 10%); --jz-polished:#2F7D4F; --jz-broken:#B42318; --jz-confused:#6E4FC2;\n --jz-shadow:0 1px 3px rgb(0 0 0 / 12%);\n font: 400 13px/1.45 Inter, ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", sans-serif;\n color: var(--jz-ink); -webkit-font-smoothing: antialiased;\n}\n@media (prefers-color-scheme: dark) {\n .jz { --jz-canvas:#111316; --jz-surface:#181B1F; --jz-raised:#20242A; --jz-ink:#E8EAED; --jz-muted:#A3A9B2;\n --jz-faint:#6F7680; --jz-rule:rgb(232 234 237 / 12%); --jz-accent:#7F9CF0; --jz-accent-ink:#111316;\n --jz-accent-soft:rgb(127 156 240 / 14%); --jz-confused:#A48BEA; --jz-polished:#5DBB84; }\n}\n.jz *, .jz *::before, .jz *::after { box-sizing: border-box; }\n/* Zero specificity: a component's own colour (.toggle, .primary, ...) must always win. */\n:where(.jz button) { font: inherit; color: inherit; cursor: pointer; }\n.jz :focus-visible { outline: 2px solid var(--jz-accent); outline-offset: 2px; }\n.mono { font-family: \"JetBrains Mono\", ui-monospace, SFMono-Regular, Menlo, monospace; }\n.sr { position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; }\n\n.toggle { position:fixed; right:32px; bottom:32px; z-index:2147483646; height:44px; padding:0 16px; display:flex; align-items:center;\n gap:8px; border:0; border-radius:999px; background:#1D2024; color:#FFFFFF; box-shadow:var(--jz-shadow); font-weight:500; }\n.toggle .dot { width:8px; height:8px; border-radius:50%; background:var(--jz-polished); }\n.toggle .exit { color:#8A9099; }\n.toggle:hover .exit { color:#FFFFFF; }\n\n.layer { position:fixed; inset:0; z-index:2147483640; pointer-events:none; }\n.hl { position:fixed; display:none; outline:1px solid var(--jz-accent); outline-offset:-1px; border-radius:2px; }\n.hl.masked { outline:1px dashed var(--jz-faint);\n background:repeating-linear-gradient(45deg, rgb(138 144 153 / 10%) 0 4px, rgb(138 144 153 / 20%) 4px 8px); }\n.tag { position:absolute; left:0; top:-18px; padding:1px 6px; border-radius:2px; background:var(--jz-accent); color:#FFFFFF;\n font-size:10px; line-height:16px; white-space:nowrap; max-width:280px; overflow:hidden; text-overflow:ellipsis; }\n.hl.masked .tag { background:var(--jz-muted); text-transform:uppercase; letter-spacing:.06em; }\n.pin { position:fixed; width:24px; height:24px; margin:-12px 0 0 -12px; border-radius:50%; display:flex; align-items:center;\n justify-content:center; background:var(--jz-accent); color:#FFFFFF; font-size:12px; font-weight:500; box-shadow:var(--jz-shadow); }\n\n.pop, .sheet, .checkin, .toast { position:fixed; z-index:2147483645; background:var(--jz-surface); color:var(--jz-ink);\n border:1px solid var(--jz-rule); box-shadow:var(--jz-shadow); }\n.pop { width:400px; max-width:calc(100vw - 32px); max-height:calc(100vh - 32px); overflow:auto; padding:24px; border-radius:10px;\n animation: jz-in 180ms ease-out; }\n@keyframes jz-in { from { opacity:0; transform:translateY(4px); } to { opacity:1; transform:none; } }\n.pop-head { display:flex; align-items:center; justify-content:space-between; gap:8px; margin-bottom:20px; }\n.pop h2 { margin:0; font-size:14px; font-weight:500; }\n.close { width:32px; height:32px; display:flex; align-items:center; justify-content:center; border:0; border-radius:6px;\n background:transparent; color:var(--jz-faint); }\n.close:hover { color:var(--jz-ink); }\n.chips { display:flex; flex-wrap:wrap; gap:8px; margin-bottom:20px; }\n.chip { display:inline-flex; align-items:center; gap:4px; padding:2px 8px; border-radius:999px; background:var(--jz-raised);\n color:var(--jz-muted); font-size:11px; }\n.reactions { display:flex; border:1px solid var(--jz-rule); border-radius:8px; overflow:hidden; margin-bottom:20px; }\n.reaction { flex:1; min-height:56px; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:4px;\n padding:12px 4px; border:0; border-right:1px solid var(--jz-rule); background:transparent; color:var(--jz-muted); }\n.reaction:last-child { border-right:0; }\n.reaction:hover { background:var(--jz-canvas); }\n.reaction span { font-size:10px; font-weight:500; }\n.reaction[data-r=\"confused\"] { color:var(--jz-confused); }\n.reaction[aria-checked=\"true\"] { background:var(--jz-accent-soft); color:var(--jz-accent); }\n.reaction[data-r=\"confused\"][aria-checked=\"true\"] { background:rgb(110 79 194 / 10%); color:var(--jz-confused); }\n.comment { display:block; width:100%; height:112px; padding:16px; margin-bottom:20px; resize:none; border:1px solid var(--jz-rule);\n border-radius:8px; background:var(--jz-surface); color:var(--jz-ink); font:inherit; }\n.comment::placeholder { color:var(--jz-faint); }\n.comment:focus { outline:none; box-shadow:0 0 0 1px var(--jz-accent); }\n.foot { display:flex; align-items:center; justify-content:space-between; gap:12px; }\n.shot { display:flex; align-items:center; gap:12px; min-width:0; }\n.thumb { flex:none; width:80px; height:48px; border-radius:8px; border:1px solid var(--jz-rule); background:var(--jz-canvas);\n overflow:hidden; display:flex; align-items:center; justify-content:center; color:var(--jz-faint); font-size:8px; }\n.thumb img { width:100%; height:100%; object-fit:cover; }\n.thumb.hatch { background:repeating-linear-gradient(45deg, rgb(138 144 153 / 10%) 0 4px, rgb(138 144 153 / 20%) 4px 8px); }\n.shot-open { display:block; width:100%; height:100%; padding:0; border:0; background:transparent; }\n.optout-row { display:flex; align-items:center; gap:8px; margin-bottom:16px; color:var(--jz-muted); font-size:12px; }\n.optout-row[hidden] { display:none; }\n.note { font-size:11px; color:var(--jz-faint); line-height:1.3; }\n.shot-full { position:fixed; inset:0; z-index:2147483647; display:flex; align-items:center; justify-content:center; padding:24px; background:rgb(0 0 0 / 72%); }\n.shot-full img { max-width:100%; max-height:100%; object-fit:contain; border-radius:6px; background:var(--jz-surface); }\n.shot-full .close { position:absolute; top:16px; right:16px; background:var(--jz-surface); color:var(--jz-ink); }\n.primary { min-height:44px; padding:0 24px; border:0; border-radius:8px; background:var(--jz-accent); color:var(--jz-accent-ink); font-weight:500; }\n.primary:disabled { opacity:.45; cursor:not-allowed; }\n.secondary { min-height:44px; padding:0 16px; border:1px solid var(--jz-rule); border-radius:6px; background:transparent;\n color:var(--jz-muted); font-weight:500; }\n\n.sheet { left:32px; bottom:32px; width:340px; max-width:calc(100vw - 32px); padding:24px; border-radius:10px; }\n.sheet h2 { display:flex; align-items:center; gap:8px; margin:0 0 12px; font-size:14px; font-weight:500; }\n.sheet h2 svg { color:var(--jz-accent); }\n.sheet p { margin:0 0 12px; color:var(--jz-muted); line-height:1.6; }\n.sheet ul { margin:0 0 20px; padding-left:18px; color:var(--jz-muted); }\n.row { display:flex; gap:8px; }\n.row > * { flex:1; }\n\n.checkin { right:32px; bottom:140px; display:flex; align-items:center; gap:8px; padding:8px 8px 8px 16px; border-radius:10px; }\n.checkin .secondary { min-height:36px; }\n.toast { right:32px; bottom:88px; padding:10px 16px; border-radius:10px; }\n.toast.err { border-color:var(--jz-broken); }\n\n@media (max-width: 479px) {\n .toggle { right:24px; bottom:24px; height:48px; padding:0 20px; background:var(--jz-accent); color:var(--jz-accent-ink); }\n .toggle .dot { background:var(--jz-accent-ink); }\n .toggle .exit { color:inherit; opacity:.8; }\n .pop { left:0 !important; right:0; top:auto !important; bottom:0; width:auto; max-width:none; max-height:85vh;\n border-radius:16px 16px 0 0; border-width:1px 0 0; padding:12px 24px 34px; }\n .pop::before { content:\"\"; display:block; width:48px; height:4px; margin:0 auto 16px; border-radius:999px; background:var(--jz-raised); }\n .chip { border-radius:4px; border:1px solid var(--jz-rule); }\n .reactions { display:grid; grid-template-columns:repeat(4, 1fr); gap:12px; border:0; overflow:visible; }\n .reaction { border:1px solid var(--jz-rule); border-radius:8px; padding:16px 4px; }\n .reaction:last-child { border-right:1px solid var(--jz-rule); }\n .reaction[aria-checked=\"true\"] { border:2px solid var(--jz-accent); }\n .reaction span { font-size:11px; }\n .foot { flex-direction:column; align-items:stretch; }\n .foot .primary { width:100%; min-height:52px; font-size:15px; }\n .sheet { left:16px; right:16px; bottom:16px; width:auto; }\n .toast { left:16px; right:16px; bottom:84px; }\n .checkin { left:16px; right:16px; bottom:136px; }\n}\n@media (prefers-reduced-motion: reduce) {\n .jz *, .jz *::before, .jz *::after { animation-duration:1ms !important; transition-duration:1ms !important; }\n}\n";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { MountOptions } from "../loader";
|
|
2
|
+
import { signedIdentity } from "../config";
|
|
3
|
+
export { signedIdentity };
|
|
4
|
+
/**
|
|
5
|
+
* The PUT target for a screenshot: `uploadUrl` is a path relative to the collector endpoint
|
|
6
|
+
* (collector.proto). Image bytes only ever go to the collector's own origin.
|
|
7
|
+
*/
|
|
8
|
+
export declare function uploadTarget(uploadUrl: string, endpoint: string): string | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Reserves and PUTs one masked image; resolves its `screenshotId`, or `undefined` when the bytes
|
|
11
|
+
* were refused. A failed reservation rejects with the collector's error (the caller decides
|
|
12
|
+
* whether uploads are unavailable). Call only after consent.
|
|
13
|
+
*/
|
|
14
|
+
export declare function putScreenshot(endpoint: string, options: MountOptions, blob: Blob, fetchImpl?: typeof fetch): Promise<string | undefined>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { WidgetModule } from "./loader";
|
|
2
|
+
import { type JourneezeContext, type WireFeedbackContext } from "./types";
|
|
3
|
+
export { maskedSnapshotSvg } from "./widget/capture";
|
|
4
|
+
export { signedIdentity, uploadTarget } from "./widget/upload";
|
|
5
|
+
/** Strips empty values; adds the page path and device class the widget derives. */
|
|
6
|
+
export declare function wireContext(ctx: Readonly<JourneezeContext>, href: string, width: number, tflowId?: string): WireFeedbackContext;
|
|
7
|
+
export declare const mount: WidgetModule["mount"];
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export declare class CollectorError extends Error {
|
|
2
|
+
readonly code: string;
|
|
3
|
+
/** HTTP status of the response (0 when there was none). */
|
|
4
|
+
readonly status: number;
|
|
5
|
+
/** The response's `Retry-After`, in milliseconds (C0b §6), when it sent one. */
|
|
6
|
+
readonly retryAfterMs?: number | undefined;
|
|
7
|
+
constructor(code: string, message: string,
|
|
8
|
+
/** HTTP status of the response (0 when there was none). */
|
|
9
|
+
status?: number,
|
|
10
|
+
/** The response's `Retry-After`, in milliseconds (C0b §6), when it sent one. */
|
|
11
|
+
retryAfterMs?: number | undefined);
|
|
12
|
+
}
|
|
13
|
+
/** The collector a v1 page talks to when the host names none (C0a §5, C0b §1: direct mode). */
|
|
14
|
+
export declare const DEFAULT_API_HOST = "https://app.journeeze.dev";
|
|
15
|
+
export declare const TIMEOUT_MS = 15000;
|
|
16
|
+
/** `init` plus a timeout signal where the browser supports `AbortSignal.timeout`. */
|
|
17
|
+
export declare function withTimeout(init: RequestInit, ms?: number): RequestInit;
|
|
18
|
+
export interface CallOptions {
|
|
19
|
+
/** Let the request finish after the page unloads (small bodies only, < 64 KB). */
|
|
20
|
+
keepalive?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The collector base URL from the v0 `endpoint` option: an explicit (relative or absolute)
|
|
24
|
+
* endpoint is resolved against the page; without one, v1 talks to the Journeeze collector
|
|
25
|
+
* directly ({@link DEFAULT_API_HOST}, C0a §5 "Change [J3c]"). A v0 host that relied on its own
|
|
26
|
+
* same-origin proxy without setting `endpoint` must now set `apiHost: location.origin`.
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolveEndpoint(endpoint: string | undefined, base?: string): string;
|
|
29
|
+
/** Whether `endpoint` is another origin than the page's (direct mode: CORS rules apply). */
|
|
30
|
+
export declare function isCrossOrigin(endpoint: string, page?: string): boolean;
|
|
31
|
+
/** The content type of every direct-mode body (C0b §2.1): CORS-safelisted, UTF-8. */
|
|
32
|
+
export declare const TEXT_PLAIN = "text/plain;charset=UTF-8";
|
|
33
|
+
/** The unary RPC URL under `endpoint`. */
|
|
34
|
+
export declare function rpcUrl(endpoint: string, method: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* The request headers of a unary call: direct mode sends only `text/plain` (a simple request, no
|
|
37
|
+
* preflight); a help read's `If-None-Match` is added in both modes (that one read preflights,
|
|
38
|
+
* and the preflight is cached for two hours). Same origin keeps Connect JSON.
|
|
39
|
+
*/
|
|
40
|
+
export declare function unaryHeaders(endpoint: string, etag?: string): Record<string, string>;
|
|
41
|
+
/** No wait (backoff or `Retry-After`) is longer than 60 s (C0b §6). */
|
|
42
|
+
export declare const RETRY_CAP_MS = 60000;
|
|
43
|
+
/** `Retry-After` (whole seconds or an HTTP date) in milliseconds, capped at 60 s (C0b §6). */
|
|
44
|
+
export declare function retryAfterMs(header: string | null, now?: number): number | undefined;
|
|
45
|
+
export declare function callCollector<Res>(endpoint: string, method: string, body: unknown, fetchImpl?: typeof fetch, opts?: CallOptions): Promise<Res>;
|
|
46
|
+
/** A help read (`GetHelpIndex`, `GetGuide`): fresh data with its ETag, or "unchanged". */
|
|
47
|
+
export type Revalidated<Res> = {
|
|
48
|
+
notModified: false;
|
|
49
|
+
value: Res;
|
|
50
|
+
etag?: string;
|
|
51
|
+
} | {
|
|
52
|
+
notModified: true;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* A read-only collector call that revalidates: sends `If-None-Match` with a previous ETag and
|
|
56
|
+
* returns `notModified` on `304`. Same rules as {@link callCollector}. Browsers do not cache
|
|
57
|
+
* POST responses: keep the last value in memory for the response's `max-age`, then revalidate.
|
|
58
|
+
*/
|
|
59
|
+
export declare function callCollectorRevalidating<Res>(endpoint: string, method: string, body: unknown, etag: string | undefined, fetchImpl?: typeof fetch): Promise<Revalidated<Res>>;
|
|
60
|
+
/** A guide asset path (relative to the collector endpoint) as an absolute URL, or `undefined`. */
|
|
61
|
+
export declare function assetUrl(endpoint: string, path: string | undefined): string | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* Connect code for an HTTP error without a Connect body (proxies, load balancers, framework
|
|
64
|
+
* rejections). A bare 404 is treated as transient (a deploy or a proxy), never as permanent.
|
|
65
|
+
*/
|
|
66
|
+
export declare function codeForStatus(status: number): string;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import{a as Te}from"./index-CwG2LrhO.js";import{j as Ae,c as Ne,w as ke}from"./consent-DckCUvYR.js";const xe=new Set(["cc-number","cc-csc","cc-exp","cc-exp-month","cc-exp-year"]),Re=new Set(["current-password","new-password"]),_e=/\b(?:password|passcode|ssn|social security(?: number)?|card number|cvc|cvv|iban|api key|secret|token)\b/,F=512,De=/(?:^|[^A-Za-z0-9_-])(?:sk-[A-Za-z0-9_-]{16,}|sk_(?:live|test)_[A-Za-z0-9]{16,}|ghp_[A-Za-z0-9]{36}|xox[bp]-[A-Za-z0-9-]{10,}|AKIA[0-9A-Z]{16}|eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]+)/,Ie=/(?:\d[ -]?){12,18}\d/g,Pe=/[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}/;function Fe(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/([A-Z])([A-Z][a-z])/g,"$1 $2").replace(/[_.\-:[\]]+/g," ").toLowerCase()}const U=e=>!!e&&_e.test(Fe(e));function Le(e){const t=e.getAttribute("autocomplete");if(t)for(const r of t.trim().toLowerCase().split(/\s+/)){if(xe.has(r))return"autocomplete_cc";if(r==="one-time-code")return"autocomplete_otp";if(Re.has(r))return"autocomplete_password"}}function $e(e){const t=[],r=e.getAttribute("aria-label");r&&t.push(r);const n=e.ownerDocument;for(const o of(e.getAttribute("aria-labelledby")??"").split(/\s+/)){const a=o?n?.getElementById(o)?.textContent:void 0;a&&t.push(a.slice(0,F))}const s=e.labels;if(s)for(const o of Array.from(s))t.push((o.textContent??"").slice(0,F));return t}function Me(e){let t="";for(const r of Array.from(e.childNodes))if(r.nodeType===3&&(t+=r.data),t.length>=F)break;return t.slice(0,F)}function Oe(e){let t=0;for(let r=0;r<e.length;r++){let n=e.charCodeAt(e.length-1-r)-48;r%2===1&&(n*=2,n>9&&(n-=9)),t+=n}return t%10===0}function Ue(e){for(const t of e.matchAll(Ie)){const r=t[0].replace(/[ -]/g,"");if(r.length>=13&&r.length<=19&&Oe(r))return true}return false}function B(e){if(/^(?:style|script)$/i.test(e.tagName))return;const t=Le(e);if(t)return t;if(e.tagName==="INPUT"&&(e.getAttribute("type")??"").trim().toLowerCase()==="password")return"input_password";if(U(e.getAttribute("name"))||U(e.id))return"name_sensitive";if($e(e).some(U))return"label_sensitive";const r=Me(e);if(r.trim()!==""){if(De.test(r))return"value_key_shaped";if(Ue(r))return"value_card_shaped";if(Pe.test(r))return"value_email_shaped"}}function Be(e){const t=e.getAttribute("data-tflow-id");if(t)return`[data-tflow-id="${X(t)}"]`;const r=e.getAttribute("data-testid");if(r)return`[data-testid="${X(r)}"]`;const n=[];for(let s=e;s&&n.length<6;s=s.parentElement){const o=s.tagName.toLowerCase();if(o==="html"||o==="body")break;const a=s.parentElement,i=a?Array.from(a.children).filter(l=>l.tagName===s.tagName).indexOf(s)+1:1;n.unshift(`${o}:nth-of-type(${i})`)}return n.join(" > ")||e.tagName.toLowerCase()}function X(e){return e.replace(/["\\]/g,"\\$&").slice(0,96)}function gr(e,t=()=>false){const r=[],n=s=>{if(t(s))return;const o=B(s);if(o){r.push({rule:o,selector:Be(s)});return}for(const a of Array.from(s.children))n(a)};for(const s of Array.from(e.children))n(s);return r}const ne="[modern-screenshot]",N=typeof window<"u",ze=N&&"Worker"in window,j=N?window.navigator?.userAgent:"",oe=j.includes("Chrome"),L=j.includes("AppleWebKit")&&!oe,V=j.includes("Firefox"),We=e=>e&&"__CONTEXT__"in e,je=e=>e.constructor.name==="CSSFontFaceRule",Ve=e=>e.constructor.name==="CSSImportRule",qe=e=>e.constructor.name==="CSSLayerBlockRule",E=e=>e.nodeType===1,I=e=>typeof e.className=="object",se=e=>e.tagName==="image",He=e=>e.tagName==="use",R=e=>E(e)&&typeof e.style<"u"&&!I(e),Xe=e=>e.nodeType===8,Ze=e=>e.nodeType===3,k=e=>e.tagName==="IMG",$=e=>e.tagName==="VIDEO",Ke=e=>e.tagName==="CANVAS",Ge=e=>e.tagName==="TEXTAREA",Ye=e=>e.tagName==="INPUT",Je=e=>e.tagName==="STYLE",Qe=e=>e.tagName==="SCRIPT",et=e=>e.tagName==="SELECT",tt=e=>e.tagName==="SLOT",rt=e=>e.tagName==="IFRAME",nt=(...e)=>console.warn(ne,...e);function ot(e){const t=e?.createElement?.("canvas");return t&&(t.height=t.width=1),!!t&&"toDataURL"in t&&!!t.toDataURL("image/webp").includes("image/webp")}const z=e=>e.startsWith("data:");function ie(e,t){if(e.match(/^[a-z]+:\/\//i))return e;if(N&&e.match(/^\/\//))return window.location.protocol+e;if(e.match(/^[a-z]+:/i)||!N)return e;const r=M().implementation.createHTMLDocument(),n=r.createElement("base"),s=r.createElement("a");return r.head.appendChild(n),r.body.appendChild(s),t&&(n.href=t),s.href=e,s.href}function M(e){return(e&&E(e)?e?.ownerDocument:e)??window.document}const O="http://www.w3.org/2000/svg";function st(e,t,r){const n=M(r).createElementNS(O,"svg");return n.setAttributeNS(null,"width",e.toString()),n.setAttributeNS(null,"height",t.toString()),n.setAttributeNS(null,"viewBox",`0 0 ${e} ${t}`),n}function it(e,t){let r=new XMLSerializer().serializeToString(e);return t&&(r=r.replace(/[\u0000-\u0008\v\f\u000E-\u001F\uD800-\uDFFF\uFFFE\uFFFF]/gu,"")),`data:image/svg+xml;charset=utf-8,${encodeURIComponent(r)}`}function at(e,t){return new Promise((r,n)=>{const s=new FileReader;s.onload=()=>r(s.result),s.onerror=()=>n(s.error),s.onabort=()=>n(new Error(`Failed read blob to ${t}`)),s.readAsDataURL(e)})}const ct=e=>at(e,"dataUrl");function A(e,t){const r=M(t).createElement("img");return r.decoding="sync",r.loading="eager",r.src=e,r}function _(e,t){return new Promise(r=>{const{timeout:n,ownerDocument:s,onError:o,onWarn:a}=t??{},i=typeof e=="string"?A(e,M(s)):e;let l=null,m=null;function c(){r(i),l&&clearTimeout(l),m?.()}if(n&&(l=setTimeout(c,n)),$(i)){const h=i.currentSrc||i.src;if(!h)return i.poster?_(i.poster,t).then(r):c();if(i.readyState>=2)return c();const g=c,f=d=>{a?.("Failed video load",h,d),o?.(d),c()};m=()=>{i.removeEventListener("loadeddata",g),i.removeEventListener("error",f)},i.addEventListener("loadeddata",g,{once:true}),i.addEventListener("error",f,{once:true})}else{const h=se(i)?i.href.baseVal:i.currentSrc||i.src;if(!h)return c();const g=async()=>{if(k(i)&&"decode"in i)try{await i.decode()}catch(d){a?.("Failed to decode image, trying to render anyway",i.dataset.originalSrc||h,d)}c()},f=d=>{a?.("Failed image load",i.dataset.originalSrc||h,d),c()};if(k(i)&&i.complete)return g();m=()=>{i.removeEventListener("load",g),i.removeEventListener("error",f)},i.addEventListener("load",g,{once:true}),i.addEventListener("error",f,{once:true})}})}async function lt(e,t){R(e)&&(k(e)||$(e)?await _(e,t):await Promise.all(["img","video"].flatMap(r=>Array.from(e.querySelectorAll(r)).map(n=>_(n,t)))))}const ae=(function(){let t=0;const r=()=>`0000${(Math.random()*36**4<<0).toString(36)}`.slice(-4);return()=>(t+=1,`u${r()}${t}`)})();function ce(e){return e?.split(",").map(t=>t.trim().replace(/"|'/g,"").toLowerCase()).filter(Boolean)}let Z=0;function ut(e){const t=`${ne}[#${Z}]`;return Z++,{time:r=>e&&console.time(`${t} ${r}`),timeEnd:r=>e&&console.timeEnd(`${t} ${r}`),warn:(...r)=>e&&nt(...r)}}function ft(e){return{cache:e?"no-cache":"force-cache"}}async function le(e,t){return We(e)?e:dt(e,{...t,autoDestruct:true})}async function dt(e,t){const{scale:r=1,workerUrl:n,workerNumber:s=1}=t||{},o=!!t?.debug,a=t?.features??true,i=e.ownerDocument??(N?window.document:void 0),l=e.ownerDocument?.defaultView??(N?window:void 0),m=new Map,c={width:0,height:0,quality:1,type:"image/png",scale:r,backgroundColor:null,style:null,filter:null,maximumCanvasSize:0,timeout:3e4,progress:null,debug:o,fetch:{requestInit:ft(t?.fetch?.bypassingCache),placeholderImage:"data:image/png;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",bypassingCache:false,...t?.fetch},fetchFn:null,font:{},drawImageInterval:100,workerUrl:null,workerNumber:s,onCloneEachNode:null,onCloneNode:null,onEmbedNode:null,onCreateForeignObjectSvg:null,includeStyleProperties:null,autoDestruct:false,...t,__CONTEXT__:true,log:ut(o),node:e,ownerDocument:i,ownerWindow:l,dpi:r===1?null:96*r,svgStyleElement:ue(i),svgDefsElement:i?.createElementNS(O,"defs"),svgStyles:new Map,defaultComputedStyles:new Map,workers:[...Array.from({length:ze&&n&&s?s:0})].map(()=>{try{const f=new Worker(n);return f.onmessage=async d=>{const{url:u,result:p}=d.data;p?m.get(u)?.resolve?.(p):m.get(u)?.reject?.(new Error(`Error receiving message from worker: ${u}`))},f.onmessageerror=d=>{const{url:u}=d.data;m.get(u)?.reject?.(new Error(`Error receiving message from worker: ${u}`))},f}catch(f){return c.log.warn("Failed to new Worker",f),null}}).filter(Boolean),fontFamilies:new Map,fontCssTexts:new Map,acceptOfImage:`${[ot(i)&&"image/webp","image/svg+xml","image/*","*/*"].filter(Boolean).join(",")};q=0.8`,requests:m,drawImageCount:0,tasks:[],features:a,isEnable:f=>f==="restoreScrollPosition"?typeof a=="boolean"?false:a[f]??false:typeof a=="boolean"?a:a[f]??true,shadowRoots:[]};c.log.time("wait until load"),await lt(e,{timeout:c.timeout,onWarn:c.log.warn}),c.log.timeEnd("wait until load");const{width:h,height:g}=mt(e,c);return c.width=h,c.height=g,c}function ue(e){if(!e)return;const t=e.createElement("style"),r=t.ownerDocument.createTextNode(`
|
|
2
|
+
.______background-clip--text {
|
|
3
|
+
background-clip: text;
|
|
4
|
+
-webkit-background-clip: text;
|
|
5
|
+
}
|
|
6
|
+
`);return t.appendChild(r),t}function mt(e,t){let{width:r,height:n}=t;if(E(e)&&(!r||!n)){const s=e.getBoundingClientRect();r=r||s.width||Number(e.getAttribute("width"))||0,n=n||s.height||Number(e.getAttribute("height"))||0}return{width:r,height:n}}async function gt(e,t){const{log:r,timeout:n,drawImageCount:s,drawImageInterval:o}=t;r.time("image to canvas");const a=await _(e,{timeout:n,onWarn:t.log.warn}),{canvas:i,context2d:l}=ht(e.ownerDocument,t),m=()=>{try{l?.drawImage(a,0,0,i.width,i.height)}catch(c){t.log.warn("Failed to drawImage",c)}};if(m(),t.isEnable("fixSvgXmlDecode"))for(let c=0;c<s;c++)await new Promise(h=>{setTimeout(()=>{l?.clearRect(0,0,i.width,i.height),m(),h()},c+o)});return t.drawImageCount=0,r.timeEnd("image to canvas"),i}function ht(e,t){const{width:r,height:n,scale:s,backgroundColor:o,maximumCanvasSize:a}=t,i=e.createElement("canvas");i.width=Math.floor(r*s),i.height=Math.floor(n*s),i.style.width=`${r}px`,i.style.height=`${n}px`,a&&(i.width>a||i.height>a)&&(i.width>a&&i.height>a?i.width>i.height?(i.height*=a/i.width,i.width=a):(i.width*=a/i.height,i.height=a):i.width>a?(i.height*=a/i.width,i.width=a):(i.width*=a/i.height,i.height=a));const l=i.getContext("2d");return l&&o&&(l.fillStyle=o,l.fillRect(0,0,i.width,i.height)),{canvas:i,context2d:l}}function fe(e,t){if(e.ownerDocument)try{const o=e.toDataURL();if(o!=="data:,")return A(o,e.ownerDocument)}catch(o){t.log.warn("Failed to clone canvas",o)}const r=e.cloneNode(false),n=e.getContext("2d"),s=r.getContext("2d");try{return n&&s&&s.putImageData(n.getImageData(0,0,e.width,e.height),0,0),r}catch(o){t.log.warn("Failed to clone canvas",o)}return r}function pt(e,t){try{if(e?.contentDocument?.documentElement)return q(e.contentDocument.documentElement,t)}catch(r){t.log.warn("Failed to clone iframe",r)}return e.cloneNode(false)}function wt(e){const t=e.cloneNode(false);return e.currentSrc&&e.currentSrc!==e.src&&(t.src=e.currentSrc,t.srcset=""),t.loading==="lazy"&&(t.loading="eager"),t}async function yt(e,t){if(e.ownerDocument&&!e.currentSrc&&e.poster)return A(e.poster,e.ownerDocument);const r=e.cloneNode(false);r.crossOrigin="anonymous",e.currentSrc&&e.currentSrc!==e.src&&(r.src=e.currentSrc);const n=r.ownerDocument;if(n){let s=true;if(await _(r,{onError:()=>s=false,onWarn:t.log.warn}),!s)return e.poster?A(e.poster,e.ownerDocument):r;r.currentTime=e.currentTime,await new Promise(a=>{r.addEventListener("seeked",a,{once:true})});const o=n.createElement("canvas");o.width=e.offsetWidth,o.height=e.offsetHeight;try{const a=o.getContext("2d");a&&a.drawImage(r,0,0,o.width,o.height)}catch(a){return t.log.warn("Failed to clone video",a),e.poster?A(e.poster,e.ownerDocument):r}return fe(o,t)}return r}function bt(e,t){return Ke(e)?fe(e,t):rt(e)?pt(e,t):k(e)?wt(e):$(e)?yt(e,t):e.cloneNode(false)}function St(e){let t=e.sandbox;if(!t){const{ownerDocument:r}=e;try{r&&(t=r.createElement("iframe"),t.id=`__SANDBOX__${ae()}`,t.width="0",t.height="0",t.style.visibility="hidden",t.style.position="fixed",r.body.appendChild(t),t.srcdoc='<!DOCTYPE html><meta charset="UTF-8"><title></title><body>',e.sandbox=t)}catch(n){e.log.warn("Failed to getSandBox",n)}}return t}const Et=["width","height","-webkit-text-fill-color"],vt=["stroke","fill"];function de(e,t,r){const{defaultComputedStyles:n}=r,s=e.nodeName.toLowerCase(),o=I(e)&&s!=="svg",a=o?vt.map(u=>[u,e.getAttribute(u)]).filter(([,u])=>u!==null):[],i=[o&&"svg",s,a.map((u,p)=>`${u}=${p}`).join(","),t].filter(Boolean).join(":");if(n.has(i))return n.get(i);const m=St(r)?.contentWindow;if(!m)return new Map;const c=m?.document;let h,g;o?(h=c.createElementNS(O,"svg"),g=h.ownerDocument.createElementNS(h.namespaceURI,s),a.forEach(([u,p])=>{g.setAttributeNS(null,u,p)}),h.appendChild(g)):h=g=c.createElement(s),g.textContent=" ",c.body.appendChild(h);const f=m.getComputedStyle(g,t),d=new Map;for(let u=f.length,p=0;p<u;p++){const w=f.item(p);Et.includes(w)||d.set(w,f.getPropertyValue(w))}return c.body.removeChild(h),n.set(i,d),d}function me(e,t,r){const n=new Map,s=[],o=new Map;if(r)for(const i of r)a(i);else for(let i=e.length,l=0;l<i;l++){const m=e.item(l);a(m)}for(let i=s.length,l=0;l<i;l++)o.get(s[l])?.forEach((m,c)=>n.set(c,m));function a(i){const l=e.getPropertyValue(i),m=e.getPropertyPriority(i),c=i.lastIndexOf("-"),h=c>-1?i.substring(0,c):void 0;if(h){let g=o.get(h);g||(g=new Map,o.set(h,g)),g.set(i,[l,m])}t.get(i)===l&&!m||(h?s.push(h):n.set(i,[l,m]))}return n}function Ct(e,t,r,n){const{ownerWindow:s,includeStyleProperties:o,currentParentNodeStyle:a}=n,i=t.style,l=s.getComputedStyle(e),m=de(e,null,n);a?.forEach((h,g)=>{m.delete(g)});const c=me(l,m,o);c.delete("transition-property"),c.delete("all"),c.delete("d"),c.delete("content"),r&&(c.delete("position"),c.delete("margin-top"),c.delete("margin-right"),c.delete("margin-bottom"),c.delete("margin-left"),c.delete("margin-block-start"),c.delete("margin-block-end"),c.delete("margin-inline-start"),c.delete("margin-inline-end"),c.set("box-sizing",["border-box",""])),c.get("background-clip")?.[0]==="text"&&t.classList.add("______background-clip--text"),oe&&(c.has("font-kerning")||c.set("font-kerning",["normal",""]),(c.get("overflow-x")?.[0]==="hidden"||c.get("overflow-y")?.[0]==="hidden")&&c.get("text-overflow")?.[0]==="ellipsis"&&e.scrollWidth===e.clientWidth&&c.set("text-overflow",["clip",""]));for(let h=i.length,g=0;g<h;g++)i.removeProperty(i.item(g));return c.forEach(([h,g],f)=>{i.setProperty(f,h,g)}),c}function Tt(e,t){(Ge(e)||Ye(e)||et(e))&&t.setAttribute("value",e.value)}const At=["::before","::after"],Nt=["::-webkit-scrollbar","::-webkit-scrollbar-button","::-webkit-scrollbar-thumb","::-webkit-scrollbar-track","::-webkit-scrollbar-track-piece","::-webkit-scrollbar-corner","::-webkit-resizer"];function kt(e,t,r,n,s){const{ownerWindow:o,svgStyleElement:a,svgStyles:i,currentNodeStyle:l}=n;if(!a||!o)return;function m(c){const h=o.getComputedStyle(e,c);let g=h.getPropertyValue("content");if(!g||g==="none")return;s?.(g),g=g.replace(/(')|(")|(counter\(.+\))/g,"");const f=[ae()],d=de(e,c,n);l?.forEach((b,S)=>{d.delete(S)});const u=me(h,d,n.includeStyleProperties);u.delete("content"),u.delete("-webkit-locale"),u.get("background-clip")?.[0]==="text"&&t.classList.add("______background-clip--text");const p=[`content: '${g}';`];if(u.forEach(([b,S],C)=>{p.push(`${C}: ${b}${S?" !important":""};`)}),p.length===1)return;try{t.className=[t.className,...f].join(" ")}catch(b){n.log.warn("Failed to copyPseudoClass",b);return}const w=p.join(`
|
|
7
|
+
`);let y=i.get(w);y||(y=[],i.set(w,y)),y.push(`.${f[0]}${c}`)}At.forEach(m),r&&Nt.forEach(m)}const K=new Set(["symbol"]);async function G(e,t,r,n,s){if(E(r)&&(Je(r)||Qe(r))||n.filter&&!n.filter(r))return;K.has(t.nodeName)||K.has(r.nodeName)?n.currentParentNodeStyle=void 0:n.currentParentNodeStyle=n.currentNodeStyle;const o=await q(r,n,false,s);n.isEnable("restoreScrollPosition")&&xt(e,o),t.appendChild(o)}async function Y(e,t,r,n){let s=e.firstChild;E(e)&&e.shadowRoot&&(s=e.shadowRoot?.firstChild,r.shadowRoots.push(e.shadowRoot));for(let o=s;o;o=o.nextSibling)if(!Xe(o))if(E(o)&&tt(o)&&typeof o.assignedNodes=="function"){const a=o.assignedNodes();for(let i=0;i<a.length;i++)await G(e,t,a[i],r,n)}else await G(e,t,o,r,n)}function xt(e,t){if(!R(e)||!R(t))return;const{scrollTop:r,scrollLeft:n}=e;if(!r&&!n)return;const{transform:s}=t.style,o=new DOMMatrix(s),{a,b:i,c:l,d:m}=o;o.a=1,o.b=0,o.c=0,o.d=1,o.translateSelf(-n,-r),o.a=a,o.b=i,o.c=l,o.d=m,t.style.transform=o.toString()}function Rt(e,t){const{backgroundColor:r,width:n,height:s,style:o}=t,a=e.style;if(r&&a.setProperty("background-color",r,"important"),n&&a.setProperty("width",`${n}px`,"important"),s&&a.setProperty("height",`${s}px`,"important"),o)for(const i in o)a[i]=o[i]}const _t=/^[\w-:]+$/;async function q(e,t,r=false,n){const{ownerDocument:s,ownerWindow:o,fontFamilies:a,onCloneEachNode:i}=t;if(s&&Ze(e))return n&&/\S/.test(e.data)&&n(e.data),s.createTextNode(e.data);if(s&&o&&E(e)&&(R(e)||I(e))){const m=await bt(e,t);if(t.isEnable("removeAbnormalAttributes")){const u=m.getAttributeNames();for(let p=u.length,w=0;w<p;w++){const y=u[w];_t.test(y)||m.removeAttribute(y)}}const c=t.currentNodeStyle=Ct(e,m,r,t);r&&Rt(m,t);let h=false;if(t.isEnable("copyScrollbar")){const u=[c.get("overflow-x")?.[0],c.get("overflow-y")?.[0]];h=u.includes("scroll")||(u.includes("auto")||u.includes("overlay"))&&(e.scrollHeight>e.clientHeight||e.scrollWidth>e.clientWidth)}const g=c.get("text-transform")?.[0],f=ce(c.get("font-family")?.[0]),d=f?u=>{g==="uppercase"?u=u.toUpperCase():g==="lowercase"?u=u.toLowerCase():g==="capitalize"&&(u=u[0].toUpperCase()+u.substring(1)),f.forEach(p=>{let w=a.get(p);w||a.set(p,w=new Set),u.split("").forEach(y=>w.add(y))})}:void 0;return kt(e,m,h,t,d),Tt(e,m),$(e)||await Y(e,m,t,d),await i?.(m),m}const l=e.cloneNode(false);return await Y(e,l,t),await i?.(l),l}function Dt(e){if(e.ownerDocument=void 0,e.ownerWindow=void 0,e.svgStyleElement=void 0,e.svgDefsElement=void 0,e.svgStyles.clear(),e.defaultComputedStyles.clear(),e.sandbox){try{e.sandbox.remove()}catch(t){e.log.warn("Failed to destroyContext",t)}e.sandbox=void 0}e.workers=[],e.fontFamilies.clear(),e.fontCssTexts.clear(),e.requests.clear(),e.tasks=[],e.shadowRoots=[]}function It(e){const{url:t,timeout:r,responseType:n,...s}=e,o=new AbortController,a=r?setTimeout(()=>o.abort(),r):void 0;return fetch(t,{signal:o.signal,...s}).then(i=>{if(!i.ok)throw new Error("Failed fetch, not 2xx response",{cause:i});switch(n){case"arrayBuffer":return i.arrayBuffer();case"dataUrl":return i.blob().then(ct);default:return i.text()}}).finally(()=>clearTimeout(a))}function D(e,t){const{url:r,requestType:n="text",responseType:s="text",imageDom:o}=t;let a=r;const{timeout:i,acceptOfImage:l,requests:m,fetchFn:c,fetch:{requestInit:h,bypassingCache:g,placeholderImage:f},font:d,workers:u,fontFamilies:p}=e;n==="image"&&(L||V)&&e.drawImageCount++;let w=m.get(r);if(!w){g&&g instanceof RegExp&&g.test(a)&&(a+=(/\?/.test(a)?"&":"?")+new Date().getTime());const y=n.startsWith("font")&&d&&d.minify,b=new Set;y&&n.split(";")[1].split(",").forEach(P=>{p.has(P)&&p.get(P).forEach(H=>b.add(H))});const S=y&&b.size,C={url:a,timeout:i,responseType:S?"arrayBuffer":s,headers:n==="image"?{accept:l}:void 0,...h};w={type:n,resolve:void 0,reject:void 0,response:null},w.response=(async()=>{if(c&&n==="image"){const v=await c(r);if(v)return v}return!L&&r.startsWith("http")&&u.length?new Promise((v,P)=>{u[m.size&u.length-1].postMessage({rawUrl:r,...C}),w.resolve=v,w.reject=P}):It(C)})().catch(v=>{if(m.delete(r),n==="image"&&f)return e.log.warn("Failed to fetch image base64, trying to use placeholder image",a),typeof f=="string"?f:f(o);throw v}),m.set(r,w)}return w.response}async function ge(e,t,r,n){if(!he(e))return e;for(const[s,o]of Pt(e,t))try{const a=await D(r,{url:o,requestType:n?"image":"text",responseType:"dataUrl"});e=e.replace(Ft(s),`$1${a}$3`)}catch(a){r.log.warn("Failed to fetch css data url",s,a)}return e}function he(e){return/url\((['"]?)([^'"]+?)\1\)/.test(e)}const pe=/url\((['"]?)([^'"]+?)\1\)/g;function Pt(e,t){const r=[];return e.replace(pe,(n,s,o)=>(r.push([o,ie(o,t)]),n)),r.filter(([n])=>!z(n))}function Ft(e){const t=e.replace(/([.*+?^${}()|\[\]\/\\])/g,"\\$1");return new RegExp(`(url\\(['"]?)(${t})(['"]?\\))`,"g")}const Lt=["background-image","border-image-source","-webkit-border-image","-webkit-mask-image","list-style-image"];function $t(e,t){return Lt.map(r=>{const n=e.getPropertyValue(r);return!n||n==="none"?null:((L||V)&&t.drawImageCount++,ge(n,null,t,true).then(s=>{!s||n===s||e.setProperty(r,s,e.getPropertyPriority(r))}))}).filter(Boolean)}function Mt(e,t){if(k(e)){const r=e.currentSrc||e.src;if(!z(r))return[D(t,{url:r,imageDom:e,requestType:"image",responseType:"dataUrl"}).then(n=>{n&&(e.srcset="",e.dataset.originalSrc=r,e.src=n||"")})];(L||V)&&t.drawImageCount++}else if(I(e)&&!z(e.href.baseVal)){const r=e.href.baseVal;return[D(t,{url:r,imageDom:e,requestType:"image",responseType:"dataUrl"}).then(n=>{n&&(e.dataset.originalSrc=r,e.href.baseVal=n||"")})]}return[]}function Ot(e,t){const{ownerDocument:r,svgDefsElement:n}=t,s=e.getAttribute("href")??e.getAttribute("xlink:href");if(!s)return[];const[o,a]=s.split("#");if(a){const i=`#${a}`,l=t.shadowRoots.reduce((m,c)=>m??c.querySelector(`svg ${i}`),r?.querySelector(`svg ${i}`));if(o&&e.setAttribute("href",i),n?.querySelector(i))return[];if(l)return n?.appendChild(l.cloneNode(true)),[];if(o)return[D(t,{url:o,responseType:"text"}).then(m=>{n?.insertAdjacentHTML("beforeend",m)})]}return[]}function we(e,t){const{tasks:r}=t;E(e)&&((k(e)||se(e))&&r.push(...Mt(e,t)),He(e)&&r.push(...Ot(e,t))),R(e)&&r.push(...$t(e.style,t)),e.childNodes.forEach(n=>{we(n,t)})}async function Ut(e,t){const{ownerDocument:r,svgStyleElement:n,fontFamilies:s,fontCssTexts:o,tasks:a,font:i}=t;if(!(!r||!n||!s.size))if(i&&i.cssText){const l=Q(i.cssText,t);n.appendChild(r.createTextNode(`${l}
|
|
8
|
+
`))}else{const l=Array.from(r.styleSheets).filter(f=>{try{return"cssRules"in f&&!!f.cssRules.length}catch(d){return t.log.warn(`Error while reading CSS rules from ${f.href}`,d),false}}),m=r.implementation.createHTMLDocument(""),c=m.createElement("style");m.head.appendChild(c);const h=c.sheet;await Promise.all(l.flatMap(f=>Array.from(f.cssRules).map(async d=>{if(Ve(d)){const u=d.href;let p="";try{p=await D(t,{url:u,requestType:"text",responseType:"text"})}catch(y){t.log.warn(`Error fetch remote css import from ${u}`,y)}const w=p.replace(pe,(y,b,S)=>y.replace(S,ie(S,u)));for(const y of zt(w))try{h.insertRule(y,h.cssRules.length)}catch(b){t.log.warn("Error inserting rule from remote css import",{rule:y,error:b})}}}))),h.cssRules.length&&l.push(h);const g=[];l.forEach(f=>{W(f.cssRules,g)}),g.filter(f=>je(f)&&he(f.style.getPropertyValue("src"))&&ce(f.style.getPropertyValue("font-family"))?.some(d=>s.has(d))).forEach(f=>{const d=f,u=o.get(d.cssText);u?n.appendChild(r.createTextNode(`${u}
|
|
9
|
+
`)):a.push(ge(d.cssText,d.parentStyleSheet?d.parentStyleSheet.href:null,t).then(p=>{p=Q(p,t),o.set(d.cssText,p),n.appendChild(r.createTextNode(`${p}
|
|
10
|
+
`))}))})}}const Bt=/(\/\*[\s\S]*?\*\/)/g,J=/((@.*?keyframes [\s\S]*?){([\s\S]*?}\s*?)})/gi;function zt(e){if(e==null)return[];const t=[];let r=e.replace(Bt,"");for(;;){const o=J.exec(r);if(!o)break;t.push(o[0])}r=r.replace(J,"");const n=/@import[\s\S]*?url\([^)]*\)[\s\S]*?;/gi,s=new RegExp("((\\s*?(?:\\/\\*[\\s\\S]*?\\*\\/)?\\s*?@media[\\s\\S]*?){([\\s\\S]*?)}\\s*?})|(([\\s\\S]*?){([\\s\\S]*?)})","gi");for(;;){let o=n.exec(r);if(o)s.lastIndex=n.lastIndex;else if(o=s.exec(r),o)n.lastIndex=s.lastIndex;else break;t.push(o[0])}return t}const Wt=/url\([^)]+\)\s*format\((["']?)([^"']+)\1\)/g,jt=/src:\s*(?:url\([^)]+\)\s*format\([^)]+\)[,;]\s*)+/g;function Q(e,t){const{font:r}=t,n=r?r?.preferredFormat:void 0;return n?e.replace(jt,s=>{for(;;){const[o,,a]=Wt.exec(s)||[];if(!a)return"";if(a===n)return`src: ${o};`}}):e}function W(e,t=[]){for(const r of Array.from(e))qe(r)?t.push(...W(r.cssRules)):"cssRules"in r?W(r.cssRules,t):t.push(r);return t}const Vt=/\bx?link:?href\s*=\s*["'](?!data:)[^"']+["']/i;function qt(e){return Vt.test(e.innerHTML)}async function ye(e,t){const r=await le(e,t);if(E(r.node)&&I(r.node)&&!qt(r.node))return r.node;const{ownerDocument:n,log:s,tasks:o,svgStyleElement:a,svgDefsElement:i,svgStyles:l,font:m,progress:c,autoDestruct:h,onCloneNode:g,onEmbedNode:f,onCreateForeignObjectSvg:d}=r;s.time("clone node");const u=await q(r.node,r,true);if(a&&n){let S="";l.forEach((C,v)=>{S+=`${C.join(`,
|
|
11
|
+
`)} {
|
|
12
|
+
${v}
|
|
13
|
+
}
|
|
14
|
+
`}),a.appendChild(n.createTextNode(S))}s.timeEnd("clone node"),await g?.(u),m!==false&&E(u)&&(s.time("embed web font"),await Ut(u,r),s.timeEnd("embed web font")),s.time("embed node"),we(u,r);const p=o.length;let w=0;const y=async()=>{for(;;){const S=o.pop();if(!S)break;try{await S}catch(C){r.log.warn("Failed to run task",C)}c?.(++w,p)}};c?.(w,p),await Promise.all([...Array.from({length:4})].map(y)),s.timeEnd("embed node"),await f?.(u);const b=Ht(u,r);return i&&b.insertBefore(i,b.children[0]),a&&b.insertBefore(a,b.children[0]),h&&Dt(r),await d?.(b),b}function Ht(e,t){const{width:r,height:n}=t,s=st(r,n,e.ownerDocument),o=s.ownerDocument.createElementNS(s.namespaceURI,"foreignObject");return o.setAttributeNS(null,"x","0%"),o.setAttributeNS(null,"y","0%"),o.setAttributeNS(null,"width","100%"),o.setAttributeNS(null,"height","100%"),o.append(e),s.appendChild(o),s}async function Xt(e,t){const r=await le(e,t),n=await ye(r),s=it(n,r.isEnable("removeControlCharacter"));r.autoDestruct||(r.svgStyleElement=ue(r.ownerDocument),r.svgDefsElement=r.ownerDocument?.createElementNS(O,"defs"),r.svgStyles.clear());const o=A(s,n.ownerDocument);return await gt(o,r)}const Zt="iframe, frame, object, embed, video, audio, canvas",Kt=e=>Te(e)||e.matches(Zt),Gt="[data-journeeze], [data-journeeze-chat]",Yt="[data-jz-block]",Jt=2*1024*1024,Qt=1600;class be extends Error{}const T=1,x=3,er=8;function Se(e,t={}){const r=[e],n=new Map,s=ir([...t.maskSelectors??[],...t.configMaskSelectors??[]]),o={},a=t.maskAllText===true,i=f=>Kt(f)||s.some(d=>{try{return f.matches(d)}catch{return true}});let l;const m=f=>{if(f.nodeType===T){const d=f;if(d.matches(Gt))return n.set(d,"drop"),false;if(d.matches(Yt))return n.set(d,"empty"),false;if(sr(d)||i(d))return n.set(d,"replace"),false;const u=B(d);if(u)return o[u]=(o[u]??0)+1,n.set(d,"replace"),false}return f.nodeType!==x&&r.push(f),true},c=f=>{const d=r.pop();if(!d||d.nodeName!==f.nodeName){l??(l="clone order mismatch");return}d.nodeType===T&&f.nodeType===T&&h(d,f)};function h(f,d){const u=Array.from(d.childNodes),p=d.ownerDocument??document;let w=0;for(const y of tr(f)){const b=n.get(y);if(b==="drop")continue;if(b==="replace"){d.insertBefore(nr(y,p),u[w]??null);continue}if(b==="empty"){d.insertBefore(or(y,p),u[w]??null);continue}const S=u[w];if(S===void 0){l??(l="missing clone child");return}w++,a&&y.nodeType===x&&S.nodeType===x&&y.data.trim()!==""&&d.replaceChild(ar(y,p),S)}w!==u.length&&(l??(l="unexpected clone child"))}return{filter:m,onCloneEachNode:c,onCloneNode:f=>{if(r.length!==0&&(l??(l="unbalanced clone traversal")),f.nodeType===T){const d=[f,...Array.from(f.querySelectorAll("*"))];d.some(u=>i(u)||B(u)!==void 0)&&(l??(l="maskable element in clone")),a&&d.some(ve)&&(l??(l="text in clone"))}if(l!==void 0)throw new be(l)},failure:()=>l,detectorCounts:()=>({...o})}}function tr(e){const t=[],r=e.shadowRoot?Array.from(e.shadowRoot.childNodes):Array.from(e.childNodes);for(const n of r)if(n.nodeType!==er){if(n.nodeType===T&&n.tagName==="SLOT"&&typeof n.assignedNodes=="function"){for(const s of n.assignedNodes())ee(s)||t.push(s);continue}ee(n)||t.push(n)}return t}function ee(e){return e.nodeType===T&&(e.tagName==="STYLE"||e.tagName==="SCRIPT")}const rr=["position","top","right","bottom","left","float","clear","z-index","margin-top","margin-right","margin-bottom","margin-left","flex-grow","flex-shrink","flex-basis","align-self","justify-self","order","grid-row-start","grid-row-end","grid-column-start","grid-column-end","vertical-align","border-top-left-radius","border-top-right-radius","border-bottom-left-radius","border-bottom-right-radius","transform","visibility"];function nr(e,t){return Ee(e,t,true)}function or(e,t){return Ee(e,t,false)}function Ee(e,t,r){const s=e.ownerDocument.defaultView?.getComputedStyle(e),o=e.getBoundingClientRect(),a=e instanceof HTMLElement?e.offsetWidth:o.width,i=e instanceof HTMLElement?e.offsetHeight:o.height,l=s?.display??"block",m=t.createElement(l.startsWith("inline")?"span":"div"),c=m.style;for(const h of rr){const g=s?.getPropertyValue(h);g&&c.setProperty(h,g)}return c.setProperty("display",l==="none"?"none":l==="inline"||l.startsWith("inline")?"inline-block":"block"),c.setProperty("box-sizing","border-box"),c.setProperty("width",`${a}px`),c.setProperty("height",`${i}px`),c.setProperty("border",r?"1px dashed #8A9099":"0"),c.setProperty("background",r?"repeating-linear-gradient(45deg, rgb(138 144 153 / 18%) 0 4px, rgb(138 144 153 / 32%) 4px 8px)":"transparent"),m.setAttribute(r?"data-jz-masked-placeholder":"data-jz-block-placeholder",""),m}function sr(e){if(!e.tagName.toLowerCase().includes("-")||e.shadowRoot)return false;const t=e.getBoundingClientRect();if(t.width<=0||t.height<=0)return false;for(const r of Array.from(e.childNodes))if(r.nodeType===T||r.nodeType===x&&r.data.trim()!=="")return false;return true}function ir(e){for(const t of e??[])try{document.createDocumentFragment().querySelector(t)}catch{throw te||console.warn("[journeeze] invalid maskSelectors entry: screenshots are off"),te=true,new be("invalid maskSelectors")}return[...e??[]]}let te=false;function ve(e){for(const t of Array.from(e.childNodes))if(t.nodeType===x&&t.data.trim()!==""||t.nodeType===T&&ve(t))return true;return false}function ar(e,t){const r=t.createRange();r.selectNodeContents(e);const n=r.getBoundingClientRect(),s=t.createElement("span"),o=s.style;return o.setProperty("display","inline-block"),o.setProperty("width",`${n.width}px`),o.setProperty("height",`${n.height}px`),o.setProperty("background","repeating-linear-gradient(45deg, rgb(138 144 153 / 18%) 0 4px, rgb(138 144 153 / 32%) 4px 8px)"),s.setAttribute("data-jz-masked-placeholder",""),s}function re(e,t){const r=parseFloat(e.ownerDocument.defaultView?.getComputedStyle(e).getPropertyValue(t)??"0");return Number.isFinite(r)?r:0}function Ce(e,t,r,n){const s=e.ownerDocument.defaultView??window;return{width:s.innerWidth,height:s.innerHeight,scale:r,quality:n,type:"image/webp",timeout:4e3,style:{marginTop:`${re(e,"margin-top")-s.scrollY}px`,marginLeft:`${re(e,"margin-left")-s.scrollX}px`},filter:t.filter,onCloneEachNode:t.onCloneEachNode,onCloneNode:t.onCloneNode}}async function hr(e=document.body,t={}){return(await cr(e,t)).blob}async function cr(e=document.body,t={}){const r=e.ownerDocument.defaultView??window,n=Math.min(r.devicePixelRatio||1,Qt/Math.max(1,r.innerWidth)),s=Se(e,t);let o=await Xt(e,Ce(e,s,n,1));const a=s.detectorCounts();for(const i of[.8,.6,.45]){const l=await lr(o,i);if(!l||l.type!=="image/webp"&&l.type!=="image/png")return{blob:void 0,detectorCounts:a};if(l.size<=Jt)return{blob:l,detectorCounts:a};o=ur(o,.75)}return{blob:void 0,detectorCounts:a}}function lr(e,t){return new Promise(r=>e.toBlob(r,"image/webp",t))}function ur(e,t){const r=e.ownerDocument.createElement("canvas");return r.width=Math.max(1,Math.round(e.width*t)),r.height=Math.max(1,Math.round(e.height*t)),r.getContext("2d")?.drawImage(e,0,0,r.width,r.height),r}async function pr(e=document.body,t={}){const r=Se(e,t),n=await ye(e,{...Ce(e,r,1,1),font:false});return new XMLSerializer().serializeToString(n)}function fr(e,t){try{const r=new URL(t.endsWith("/")?t:`${t}/`),n=new URL(e.replace(/^\/+/,""),r);return n.origin===r.origin?n.href:void 0}catch{return}}async function wr(e,t,r,n=(...s)=>fetch(...s)){if(r.type!=="image/webp"&&r.type!=="image/png")return;const s={siteKey:t.siteKey,contentType:r.type,byteLength:r.size,...t.reviewerToken?{reviewerToken:t.reviewerToken}:{},...t.userId?{userId:t.userId,consentGiven:true,...Ae(t)}:{}},o=await Ne(e,"CreateScreenshotUpload",s,n),a=typeof o.uploadUrl=="string"?fr(o.uploadUrl,e):void 0;if(typeof o.screenshotId!="string"||!a)return;const i={"content-type":r.type};for(const[m,c]of Object.entries(o.headers??{}))typeof c=="string"&&(i[m]=c);return(await n(a,ke({method:"PUT",body:r,headers:i,credentials:"omit",cache:"no-store",referrerPolicy:"no-referrer"}))).ok?o.screenshotId:void 0}export{cr as a,hr as c,pr as m,wr as p,gr as s,fr as u};
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
var $=Object.defineProperty;var N=(d,t,e)=>t in d?$(d,t,{enumerable:true,configurable:true,writable:true,value:e}):d[t]=e;var n=(d,t,e)=>N(d,typeof t!="symbol"?t+"":t,e);import{e as B,s as W,d as K,h as _,f as O,C as M,D as H,g as q,i as Y,j as G}from"./consent-DckCUvYR.js";import{i as R}from"./index-CwG2LrhO.js";import{c as J,s as V,p as X}from"./upload-Fu2qvSJV.js";import{m as jt,u as zt}from"./upload-Fu2qvSJV.js";import{s as Z,R as Q}from"./hook-DGWypoEO.js";import{d as tt,i as I,e as et,a as ot}from"./anchor-cPvFFTOS.js";import{feedbackChannel as it,widgetConfig as st}from"./feedback-CtH1a_kQ.js";const S="jz:preview",w="mask-audit";function nt(){try{const d=new URL(location.href),t=d.searchParams.get("jz_preview");return t===null?sessionStorage.getItem(S)===w:(d.searchParams.delete("jz_preview"),history.replaceState(history.state,"",d.href),t===w?sessionStorage.setItem(S,w):sessionStorage.removeItem(S),t===w)}catch{return false}}const U='<path d="M9 9h.01"/><path d="M15 9h.01"/>',rt={like:`<circle cx="12" cy="12" r="10"/><path d="M8 14s1.5 2 4 2 4-2 4-2"/>${U}`,dislike:`<circle cx="12" cy="12" r="10"/><path d="M16 16s-1.5-2-4-2-4 2-4 2"/>${U}`,understood:'<circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/>',confused:'<circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><path d="M12 17h.01"/>',close:'<path d="M18 6 6 18"/><path d="m6 6 12 12"/>',persona:'<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/>',step:'<path d="M5 12h14"/><path d="m12 5 7 7-7 7"/>',info:'<circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/>'};function m(d,t=20){const e=document.createElement("template");return e.innerHTML=`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">${rt[d]}</svg>`,e.content.firstElementChild}const at=`
|
|
2
|
+
:host { all: initial; }
|
|
3
|
+
.jz {
|
|
4
|
+
--jz-canvas:#F7F7F5; --jz-surface:#FFFFFF; --jz-raised:#F0F0EC; --jz-ink:#1D2024; --jz-muted:#5D636B;
|
|
5
|
+
--jz-faint:#8A9099; --jz-rule:rgb(29 32 36 / 12%); --jz-accent:#3D63C9; --jz-accent-ink:#FFFFFF;
|
|
6
|
+
--jz-accent-soft:rgb(61 99 201 / 10%); --jz-polished:#2F7D4F; --jz-broken:#B42318; --jz-confused:#6E4FC2;
|
|
7
|
+
--jz-shadow:0 1px 3px rgb(0 0 0 / 12%);
|
|
8
|
+
font: 400 13px/1.45 Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
9
|
+
color: var(--jz-ink); -webkit-font-smoothing: antialiased;
|
|
10
|
+
}
|
|
11
|
+
@media (prefers-color-scheme: dark) {
|
|
12
|
+
.jz { --jz-canvas:#111316; --jz-surface:#181B1F; --jz-raised:#20242A; --jz-ink:#E8EAED; --jz-muted:#A3A9B2;
|
|
13
|
+
--jz-faint:#6F7680; --jz-rule:rgb(232 234 237 / 12%); --jz-accent:#7F9CF0; --jz-accent-ink:#111316;
|
|
14
|
+
--jz-accent-soft:rgb(127 156 240 / 14%); --jz-confused:#A48BEA; --jz-polished:#5DBB84; }
|
|
15
|
+
}
|
|
16
|
+
.jz *, .jz *::before, .jz *::after { box-sizing: border-box; }
|
|
17
|
+
/* Zero specificity: a component's own colour (.toggle, .primary, ...) must always win. */
|
|
18
|
+
:where(.jz button) { font: inherit; color: inherit; cursor: pointer; }
|
|
19
|
+
.jz :focus-visible { outline: 2px solid var(--jz-accent); outline-offset: 2px; }
|
|
20
|
+
.mono { font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
21
|
+
.sr { position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; }
|
|
22
|
+
|
|
23
|
+
.toggle { position:fixed; right:32px; bottom:32px; z-index:2147483646; height:44px; padding:0 16px; display:flex; align-items:center;
|
|
24
|
+
gap:8px; border:0; border-radius:999px; background:#1D2024; color:#FFFFFF; box-shadow:var(--jz-shadow); font-weight:500; }
|
|
25
|
+
.toggle .dot { width:8px; height:8px; border-radius:50%; background:var(--jz-polished); }
|
|
26
|
+
.toggle .exit { color:#8A9099; }
|
|
27
|
+
.toggle:hover .exit { color:#FFFFFF; }
|
|
28
|
+
|
|
29
|
+
.layer { position:fixed; inset:0; z-index:2147483640; pointer-events:none; }
|
|
30
|
+
.hl { position:fixed; display:none; outline:1px solid var(--jz-accent); outline-offset:-1px; border-radius:2px; }
|
|
31
|
+
.hl.masked { outline:1px dashed var(--jz-faint);
|
|
32
|
+
background:repeating-linear-gradient(45deg, rgb(138 144 153 / 10%) 0 4px, rgb(138 144 153 / 20%) 4px 8px); }
|
|
33
|
+
.tag { position:absolute; left:0; top:-18px; padding:1px 6px; border-radius:2px; background:var(--jz-accent); color:#FFFFFF;
|
|
34
|
+
font-size:10px; line-height:16px; white-space:nowrap; max-width:280px; overflow:hidden; text-overflow:ellipsis; }
|
|
35
|
+
.hl.masked .tag { background:var(--jz-muted); text-transform:uppercase; letter-spacing:.06em; }
|
|
36
|
+
.pin { position:fixed; width:24px; height:24px; margin:-12px 0 0 -12px; border-radius:50%; display:flex; align-items:center;
|
|
37
|
+
justify-content:center; background:var(--jz-accent); color:#FFFFFF; font-size:12px; font-weight:500; box-shadow:var(--jz-shadow); }
|
|
38
|
+
|
|
39
|
+
.pop, .sheet, .checkin, .toast { position:fixed; z-index:2147483645; background:var(--jz-surface); color:var(--jz-ink);
|
|
40
|
+
border:1px solid var(--jz-rule); box-shadow:var(--jz-shadow); }
|
|
41
|
+
.pop { width:400px; max-width:calc(100vw - 32px); max-height:calc(100vh - 32px); overflow:auto; padding:24px; border-radius:10px;
|
|
42
|
+
animation: jz-in 180ms ease-out; }
|
|
43
|
+
@keyframes jz-in { from { opacity:0; transform:translateY(4px); } to { opacity:1; transform:none; } }
|
|
44
|
+
.pop-head { display:flex; align-items:center; justify-content:space-between; gap:8px; margin-bottom:20px; }
|
|
45
|
+
.pop h2 { margin:0; font-size:14px; font-weight:500; }
|
|
46
|
+
.close { width:32px; height:32px; display:flex; align-items:center; justify-content:center; border:0; border-radius:6px;
|
|
47
|
+
background:transparent; color:var(--jz-faint); }
|
|
48
|
+
.close:hover { color:var(--jz-ink); }
|
|
49
|
+
.chips { display:flex; flex-wrap:wrap; gap:8px; margin-bottom:20px; }
|
|
50
|
+
.chip { display:inline-flex; align-items:center; gap:4px; padding:2px 8px; border-radius:999px; background:var(--jz-raised);
|
|
51
|
+
color:var(--jz-muted); font-size:11px; }
|
|
52
|
+
.reactions { display:flex; border:1px solid var(--jz-rule); border-radius:8px; overflow:hidden; margin-bottom:20px; }
|
|
53
|
+
.reaction { flex:1; min-height:56px; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:4px;
|
|
54
|
+
padding:12px 4px; border:0; border-right:1px solid var(--jz-rule); background:transparent; color:var(--jz-muted); }
|
|
55
|
+
.reaction:last-child { border-right:0; }
|
|
56
|
+
.reaction:hover { background:var(--jz-canvas); }
|
|
57
|
+
.reaction span { font-size:10px; font-weight:500; }
|
|
58
|
+
.reaction[data-r="confused"] { color:var(--jz-confused); }
|
|
59
|
+
.reaction[aria-checked="true"] { background:var(--jz-accent-soft); color:var(--jz-accent); }
|
|
60
|
+
.reaction[data-r="confused"][aria-checked="true"] { background:rgb(110 79 194 / 10%); color:var(--jz-confused); }
|
|
61
|
+
.comment { display:block; width:100%; height:112px; padding:16px; margin-bottom:20px; resize:none; border:1px solid var(--jz-rule);
|
|
62
|
+
border-radius:8px; background:var(--jz-surface); color:var(--jz-ink); font:inherit; }
|
|
63
|
+
.comment::placeholder { color:var(--jz-faint); }
|
|
64
|
+
.comment:focus { outline:none; box-shadow:0 0 0 1px var(--jz-accent); }
|
|
65
|
+
.foot { display:flex; align-items:center; justify-content:space-between; gap:12px; }
|
|
66
|
+
.shot { display:flex; align-items:center; gap:12px; min-width:0; }
|
|
67
|
+
.thumb { flex:none; width:80px; height:48px; border-radius:8px; border:1px solid var(--jz-rule); background:var(--jz-canvas);
|
|
68
|
+
overflow:hidden; display:flex; align-items:center; justify-content:center; color:var(--jz-faint); font-size:8px; }
|
|
69
|
+
.thumb img { width:100%; height:100%; object-fit:cover; }
|
|
70
|
+
.thumb.hatch { background:repeating-linear-gradient(45deg, rgb(138 144 153 / 10%) 0 4px, rgb(138 144 153 / 20%) 4px 8px); }
|
|
71
|
+
.shot-open { display:block; width:100%; height:100%; padding:0; border:0; background:transparent; }
|
|
72
|
+
.optout-row { display:flex; align-items:center; gap:8px; margin-bottom:16px; color:var(--jz-muted); font-size:12px; }
|
|
73
|
+
.optout-row[hidden] { display:none; }
|
|
74
|
+
.note { font-size:11px; color:var(--jz-faint); line-height:1.3; }
|
|
75
|
+
.shot-full { position:fixed; inset:0; z-index:2147483647; display:flex; align-items:center; justify-content:center; padding:24px; background:rgb(0 0 0 / 72%); }
|
|
76
|
+
.shot-full img { max-width:100%; max-height:100%; object-fit:contain; border-radius:6px; background:var(--jz-surface); }
|
|
77
|
+
.shot-full .close { position:absolute; top:16px; right:16px; background:var(--jz-surface); color:var(--jz-ink); }
|
|
78
|
+
.primary { min-height:44px; padding:0 24px; border:0; border-radius:8px; background:var(--jz-accent); color:var(--jz-accent-ink); font-weight:500; }
|
|
79
|
+
.primary:disabled { opacity:.45; cursor:not-allowed; }
|
|
80
|
+
.secondary { min-height:44px; padding:0 16px; border:1px solid var(--jz-rule); border-radius:6px; background:transparent;
|
|
81
|
+
color:var(--jz-muted); font-weight:500; }
|
|
82
|
+
|
|
83
|
+
.sheet { left:32px; bottom:32px; width:340px; max-width:calc(100vw - 32px); padding:24px; border-radius:10px; }
|
|
84
|
+
.sheet h2 { display:flex; align-items:center; gap:8px; margin:0 0 12px; font-size:14px; font-weight:500; }
|
|
85
|
+
.sheet h2 svg { color:var(--jz-accent); }
|
|
86
|
+
.sheet p { margin:0 0 12px; color:var(--jz-muted); line-height:1.6; }
|
|
87
|
+
.sheet ul { margin:0 0 20px; padding-left:18px; color:var(--jz-muted); }
|
|
88
|
+
.row { display:flex; gap:8px; }
|
|
89
|
+
.row > * { flex:1; }
|
|
90
|
+
|
|
91
|
+
.checkin { right:32px; bottom:140px; display:flex; align-items:center; gap:8px; padding:8px 8px 8px 16px; border-radius:10px; }
|
|
92
|
+
.checkin .secondary { min-height:36px; }
|
|
93
|
+
.toast { right:32px; bottom:88px; padding:10px 16px; border-radius:10px; }
|
|
94
|
+
.toast.err { border-color:var(--jz-broken); }
|
|
95
|
+
|
|
96
|
+
@media (max-width: 479px) {
|
|
97
|
+
.toggle { right:24px; bottom:24px; height:48px; padding:0 20px; background:var(--jz-accent); color:var(--jz-accent-ink); }
|
|
98
|
+
.toggle .dot { background:var(--jz-accent-ink); }
|
|
99
|
+
.toggle .exit { color:inherit; opacity:.8; }
|
|
100
|
+
.pop { left:0 !important; right:0; top:auto !important; bottom:0; width:auto; max-width:none; max-height:85vh;
|
|
101
|
+
border-radius:16px 16px 0 0; border-width:1px 0 0; padding:12px 24px 34px; }
|
|
102
|
+
.pop::before { content:""; display:block; width:48px; height:4px; margin:0 auto 16px; border-radius:999px; background:var(--jz-raised); }
|
|
103
|
+
.chip { border-radius:4px; border:1px solid var(--jz-rule); }
|
|
104
|
+
.reactions { display:grid; grid-template-columns:repeat(4, 1fr); gap:12px; border:0; overflow:visible; }
|
|
105
|
+
.reaction { border:1px solid var(--jz-rule); border-radius:8px; padding:16px 4px; }
|
|
106
|
+
.reaction:last-child { border-right:1px solid var(--jz-rule); }
|
|
107
|
+
.reaction[aria-checked="true"] { border:2px solid var(--jz-accent); }
|
|
108
|
+
.reaction span { font-size:11px; }
|
|
109
|
+
.foot { flex-direction:column; align-items:stretch; }
|
|
110
|
+
.foot .primary { width:100%; min-height:52px; font-size:15px; }
|
|
111
|
+
.sheet { left:16px; right:16px; bottom:16px; width:auto; }
|
|
112
|
+
.toast { left:16px; right:16px; bottom:84px; }
|
|
113
|
+
.checkin { left:16px; right:16px; bottom:136px; }
|
|
114
|
+
}
|
|
115
|
+
@media (prefers-reduced-motion: reduce) {
|
|
116
|
+
.jz *, .jz *::before, .jz *::after { animation-duration:1ms !important; transition-duration:1ms !important; }
|
|
117
|
+
}
|
|
118
|
+
`,ct=[["like","Like"],["dislike","Dislike"],["understood","Understood"],["confused","Confused"]],dt=5e3;function s(d,t={},...e){const o=document.createElement(d);for(const[i,r]of Object.entries(t))r===void 0||r===false||o.setAttribute(i,r===true?"":r);return o.append(...e),o}function ht(d,t,e,o){const i={pagePath:W(t),device:d.device||tt(e)},r=a=>{const c=d[a];typeof c=="string"&&c.trim()!==""&&(i[a]=c.trim())};return r("persona"),r("journeyId"),r("journeyStep"),r("businessType"),r("state"),o!==void 0&&(i.tflowId=o),i}class lt{constructor(t,e,o){n(this,"options");n(this,"getContext");n(this,"exit");n(this,"host",s("div",{"data-journeeze":""}));n(this,"root");n(this,"shell",s("div",{class:"jz"}));n(this,"layer",s("div",{class:"layer"}));n(this,"highlight",s("div",{class:"hl"}));n(this,"tag",s("div",{class:"tag mono"}));n(this,"live",s("div",{class:"sr","aria-live":"polite"}));n(this,"toggle");n(this,"channel");n(this,"outbox");n(this,"endpoint");n(this,"cleanups",[]);n(this,"phase","consent");n(this,"config",{});n(this,"pinCount",0);n(this,"popover");n(this,"fullShot");n(this,"fullShotOpener");n(this,"consentSheet");n(this,"checkin");n(this,"toastEl");n(this,"toastTimer");n(this,"lastCtx");n(this,"lastWhere");n(this,"askedSteps",new Set);n(this,"objectUrls",[]);n(this,"disposed",false);n(this,"exitTimer");n(this,"screenshotsUnavailable",false);n(this,"uploadNotFound",0);n(this,"pending",new Set);n(this,"signals");n(this,"configReady",Promise.resolve());n(this,"configLoaded",false);n(this,"maskAuditOn");this.options=t,this.getContext=e,this.exit=o,this.endpoint=K(t),this.signals=Z(t,this.endpoint,e),this.root=this.host.attachShadow({mode:"closed"}),this.root.append(s("style",t.nonce?{nonce:t.nonce}:{},at),this.shell),this.toggle=s("button",{type:"button",class:"toggle","aria-pressed":"true","aria-label":"Feedback mode on. Exit feedback mode"},s("span",{class:"dot","aria-hidden":"true"}),s("span",{},"Feedback mode on"),s("span",{class:"exit","aria-hidden":"true"},"· Exit")),this.toggle.addEventListener("click",()=>this.exit());for(const i of["keydown","keyup","keypress"])this.shell.addEventListener(i,r=>this.onWidgetKey(r));this.highlight.append(this.tag),this.layer.append(this.highlight),this.shell.append(this.layer,this.toggle,this.live),this.channel=it(t,this.endpoint,{beforePersist:()=>this.stashPending(),onDropped:i=>this.toast(pt(i),true)}),this.outbox=this.channel.outbox,document.body.append(this.host),this.listen(window,"keydown",i=>this.onKey(i)),this.lastCtx={...e()},this.lastWhere=j(),this.configReady=this.loadConfig(),this.maskAuditOn=!!t.reviewerToken&&nt(),this.maskAuditOn&&this.configReady.then(()=>this.maskAudit()),_(O(t))?this.startPointing():this.showConsent()}api(){return{unmount:t=>this.dispose(t),contextChanged:()=>this.onContextChanged()}}listen(t,e,o,i=false,r=false){t.addEventListener(e,o,{capture:i,passive:r}),this.cleanups.push(()=>t.removeEventListener(e,o,{capture:i}))}dispose(t){if(!this.disposed){this.disposed=true,this.signals.stop(t);for(const e of this.cleanups.splice(0))e();this.exitTimer!==void 0&&clearTimeout(this.exitTimer),this.stashPending(),this.channel.dispose(),this.toastTimer!==void 0&&clearTimeout(this.toastTimer);for(const e of this.objectUrls.splice(0))URL.revokeObjectURL(e);this.host.remove()}}async loadConfig(){try{if(this.config=await st(this.endpoint,this.options.siteKey),this.configLoaded=true,this.config.consentText&&this.consentSheet){const t=this.consentSheet.querySelector("p");t&&(t.textContent=this.config.consentText)}this.config.enabled!==true&&(this.toast("Feedback isn't switched on for this site yet.",true),this.exitTimer=setTimeout(()=>{this.disposed||this.exit()},2500))}catch(t){t instanceof M&&t.status===404&&(this.toast("Feedback isn't set up on this site yet.",true),this.exitTimer=setTimeout(()=>{this.disposed||this.exit()},2500))}}showConsent(){this.phase="consent";const t=s("h2",{id:"jz-consent-title"},m("info",18),"Suggest an improvement"),e=s("button",{type:"button",class:"primary"},"Allow and continue"),o=s("button",{type:"button",class:"secondary"},"Not now"),i=s("div",{class:"sheet",role:"dialog","aria-modal":"false","aria-labelledby":"jz-consent-title"},t,s("p",{},this.config.consentText||(this.screenshotsAllowed()?H:q)),s("div",{class:"row"},e,o));e.addEventListener("click",()=>{Y(O(this.options)),i.remove(),this.consentSheet=void 0,this.startPointing(),this.toggle.focus()}),o.addEventListener("click",()=>this.exit()),this.trapTab(i),this.consentSheet=i,this.shell.append(i),e.focus()}startPointing(){this.phase="pointing",this.signals.start(this.configReady.then(()=>this.config)),this.announce("Feedback mode on. Click any part of the page to comment on it. Press Escape to exit."),this.listen(document,"pointermove",t=>this.onMove(t),true,true);for(const t of["pointerdown","mousedown","mouseup","pointerup"])this.listen(window,t,e=>this.swallow(e),true);for(const t of["touchstart","touchend"])this.listen(window,t,e=>{this.phase==="pointing"&&this.targetOf(e)&&e.stopPropagation()},true,true);this.listen(window,"click",t=>this.onClick(t),true),this.listen(window,"scroll",()=>this.reposition(),true,true),this.listen(window,"resize",()=>this.reposition(),false,true),this.outbox.flush()}targetOf(t){const e=t.composedPath();if(e.includes(this.host))return;const o=e[0];return o instanceof Element?o:void 0}swallow(t){this.phase!=="pointing"||!t.isTrusted||!this.targetOf(t)||(t.preventDefault(),t.stopPropagation())}onMove(t){const e=this.phase==="pointing"?this.targetOf(t):void 0;if(!e){this.highlight.style.display="none";return}const o=e.getBoundingClientRect(),i=R(e)||I(e);Object.assign(this.highlight.style,{display:"block",left:`${o.left}px`,top:`${o.top}px`,width:`${o.width}px`,height:`${o.height}px`}),this.highlight.classList.toggle("masked",i),this.tag.textContent=i?"Masked":et(e),this.tag.style.top=o.top<20?"0":"-18px"}onClick(t){if(this.phase!=="pointing"||!t.isTrusted)return;const e=this.targetOf(t);e&&(t.preventDefault(),t.stopPropagation(),t.stopImmediatePropagation(),this.highlight.style.display="none",!I(e)&&this.openPopover(e,t.clientX,t.clientY))}openPopover(t,e,o){this.phase="composing";const i=this.screenshotsUnavailable||!this.screenshotsAllowed()?Promise.resolve(void 0):this.configReady.then(()=>this.configLoaded?J(document.body,this.maskOptions()):void 0).catch(()=>{}),r=ot(t,e,o),a=s("div",{class:"pin","aria-hidden":"true"},String(++this.pinCount));let c;const h=s("h2",{id:"jz-pop-title"},"How does this feel?"),f=s("button",{type:"button",class:"close","aria-label":"Close without sending"},m("close")),x=s("div",{class:"chips"}),g=this.getContext(),D=j(),F=(l,u,p)=>x.append(s("span",{class:"chip","aria-label":`${u}: ${p}`},m(l,12),p));g.persona&&F("persona","Persona",g.persona),g.journeyStep&&F("step","Journey step",g.journeyStep);const C=s("div",{class:"reactions",role:"radiogroup","aria-label":"Reaction"}),E=ct.map(([l,u])=>{const p=s("button",{type:"button",class:"reaction",role:"radio","aria-checked":"false","data-r":l},m(l),s("span",{},u));return p.addEventListener("click",()=>{c=c===l?void 0:l;for(const L of E)L.setAttribute("aria-checked",String(L.dataset.r===c));z()}),C.append(p),p}),y=s("textarea",{class:"comment","aria-label":"Comment (optional)",placeholder:"What could be improved?",maxlength:"4000"}),v=s("div",{class:"thumb hatch mono"},"CAPTURING"),T=s("span",{class:"note"},"Masked fields are hidden"),A=s("input",{type:"checkbox",class:"optout"}),P=s("label",{class:"optout-row",hidden:true},A,"Don't include screenshot"),b=s("button",{type:"button",class:"primary"},"Send"),k=s("div",{class:"pop",role:"dialog","aria-modal":"false","aria-labelledby":"jz-pop-title"},s("div",{class:"pop-head"},h,f),x,C,y,P,s("div",{class:"foot"},s("div",{class:"shot"},v,T),b)),z=()=>{b.disabled=c===void 0&&y.value.trim()===""};y.addEventListener("input",z),z(),i.then(l=>{if(this.popover?.el===k)if(v.textContent="",l){const u=URL.createObjectURL(l);this.objectUrls.push(u),v.classList.remove("hatch");const p=s("button",{type:"button",class:"shot-open","aria-label":"View screenshot full size"},s("img",{referrerpolicy:"no-referrer",src:u,alt:"Screenshot of this page with masked fields hidden"}));p.addEventListener("click",()=>this.openFullShot(u,p)),v.append(p),P.hidden=false}else v.textContent="No screenshot attached",T.textContent="Screenshot unavailable; your feedback still sends"}),f.addEventListener("click",()=>this.closePopover()),b.addEventListener("click",()=>{if(b.disabled)return;b.disabled=true;const l=y.value.trim(),u=!A.checked;this.closePopover(),this.deliver(r,c,l,u?i:Promise.resolve(void 0),g,D)}),this.trapTab(k),this.popover={el:k,pin:a,target:t,anchor:r},this.layer.append(a),this.shell.append(k),this.reposition(),E[0]?.focus()}closePopover(){if(this.popover){this.closeFullShot(),this.popover.el.remove(),this.popover.pin.remove(),this.popover=void 0;for(const t of this.objectUrls.splice(0))URL.revokeObjectURL(t);this.phase="pointing",this.toggle.focus()}}openFullShot(t,e){if(this.fullShot)return;const o=s("button",{type:"button",class:"close","aria-label":"Close full-size screenshot"},m("close")),i=s("div",{class:"shot-full",role:"dialog","aria-modal":"true","aria-label":"Screenshot"},s("img",{referrerpolicy:"no-referrer",src:t,alt:"Screenshot of this page with masked fields hidden"}),o);o.addEventListener("click",()=>this.closeFullShot()),this.trapTab(i),this.fullShot=i,this.fullShotOpener=e,this.shell.append(i),o.focus()}closeFullShot(){const t=this.fullShot;if(!t)return;this.fullShot=void 0,t.remove();const e=this.fullShotOpener;this.fullShotOpener=void 0,e?.focus()}maskOptions(){const{maskSelectors:t,maskAllText:e}=this.options,o=Array.isArray(this.config.maskSelectors)?this.config.maskSelectors:[];return{...t?{maskSelectors:t}:{},...o.length?{configMaskSelectors:o}:{},...e?{maskAllText:e}:{}}}reposition(){const t=this.popover;if(!t||!t.target.isConnected)return;const e=t.target.getBoundingClientRect(),o=e.left+t.anchor.xRatio*e.width,i=e.top+t.anchor.yRatio*e.height;if(Object.assign(t.pin.style,{left:`${o}px`,top:`${i}px`}),window.innerWidth<480)return;const r=t.el.getBoundingClientRect(),a=16;let c=e.right+a;c+r.width>window.innerWidth-a&&(c=e.left-a-r.width),c<a&&(c=Math.min(Math.max(a,o+a),window.innerWidth-r.width-a));const h=Math.min(Math.max(a,i-24),window.innerHeight-r.height-a);Object.assign(t.el.style,{left:`${Math.max(a,c)}px`,top:`${Math.max(a,h)}px`})}maskAudit(){if(this.disposed||!this.configLoaded||this.config.enabled!==true||!this.options.reviewerToken)return;const t=[...this.options.maskSelectors??[],...Array.isArray(this.config.maskSelectors)?this.config.maskSelectors:[]],{endpoint:e}=this,{siteKey:o,reviewerToken:i}=this.options;import("./mask-audit-Du3NPoG_.js").then(r=>this.disposed?0:r.runMaskAudit({scan:V,endpoint:e,siteKey:o,reviewerToken:i,maskSelectors:t})).catch(()=>{})}onContextChanged(){this.signals.contextChanged(),this.maskAuditOn&&this.maskAudit();const t=this.getContext();if(t.journeyStep===this.lastCtx.journeyStep&&t.journeyId===this.lastCtx.journeyId)return;const e=this.lastCtx,o=this.lastWhere;this.lastCtx={...t},this.lastWhere=j(),this.checkin?.remove(),this.checkin=void 0,this.maybeCheckin(e,o)}maybeCheckin(t,e){const o=t,i=o.journeyStep;if(this.phase==="consent"||!i)return;const r=`${o.journeyId??""}/${i}`;if(this.askedSteps.has(r))return;this.askedSteps.add(r),this.checkin?.remove();const a=(f,x)=>{const g=s("button",{type:"button",class:"secondary"},m(f,16),x);return g.addEventListener("click",()=>{h.remove(),this.deliver(void 0,f,"",Promise.resolve(void 0),t,e)}),g},c=s("button",{type:"button",class:"close","aria-label":"Dismiss"},m("close",16)),h=s("div",{class:"checkin",role:"group","aria-label":"Step check-in"},s("span",{},"Did this step make sense?"),a("understood","Understood"),a("confused","Confused"),c);c.addEventListener("click",()=>h.remove()),this.checkin=h,this.shell.append(h)}async deliver(t,e,o,i,r=this.getContext(),a=j()){const c={siteKey:this.options.siteKey,consentGiven:true,context:ht(r,a.href,a.width,t?.tflowId)};this.options.userId!==void 0&&Object.assign(c,{userId:this.options.userId},G(this.options)),t&&(c.anchor=t),e&&(c.reaction=Q[e]),o&&(c.comment=o);const h={request:c,stashed:false};this.pending.add(h);const f=await this.uploadScreenshot(i);if(this.pending.delete(h),h.stashed||this.disposed)return;f&&(c.screenshotId=f);const x=await this.outbox.enqueue(c);this.disposed||(x==="sent"?this.toast("Sent. Thank you."):x==="queued"&&this.toast("Saved. It will send when you're back online."))}stashPending(){for(const t of this.pending)t.stashed=true,this.outbox.stash(t.request);this.pending.clear()}screenshotsAllowed(){return!!(this.options.reviewerToken||this.options.userId)}async uploadScreenshot(t){if(!this.screenshotsUnavailable)try{let e;const o=await Promise.race([t,new Promise(r=>e=setTimeout(()=>r(void 0),dt))]).finally(()=>clearTimeout(e));if(!o)return;const i=await X(this.endpoint,this.options,o);return this.uploadNotFound=0,i}catch(e){e instanceof M&&(this.uploadNotFound=e.status===404?this.uploadNotFound+1:0,(e.code==="unimplemented"||this.uploadNotFound>=3)&&(this.screenshotsUnavailable=true));return}}onKey(t){if(t.key!=="Escape")return;const e=t.composedPath()[0];if(t.defaultPrevented||e instanceof Element&&R(e))return;const o=document.activeElement;o&&o!==document.body&&o!==document.documentElement&&o!==this.host||(this.popover?this.closePopover():this.exit())}onWidgetKey(t){if(t.stopPropagation(),t.type!=="keydown"||t.key!=="Escape")return;if(this.fullShot){this.closeFullShot();return}const e=t.target;if(e instanceof HTMLTextAreaElement&&e.value.trim()!==""&&this.popover){this.popover.el.querySelector(".close")?.focus();return}this.popover?this.closePopover():this.exit()}trapTab(t){t.addEventListener("keydown",e=>{if(e.key!=="Tab")return;const o=Array.from(t.querySelectorAll("button:not([disabled]), textarea")),i=o[0],r=o[o.length-1],a=this.root.activeElement;!i||!r||(e.shiftKey&&a===i?(e.preventDefault(),r.focus()):!e.shiftKey&&a===r&&(e.preventDefault(),i.focus()))})}announce(t){this.live.textContent=t}toast(t,e=false){this.toastEl?.remove(),this.toastTimer!==void 0&&clearTimeout(this.toastTimer);const o=s("div",{class:e?"toast err":"toast",role:"status"},t);this.toastEl=o,this.shell.append(o),this.toastTimer=setTimeout(()=>o.remove(),e?6e3:3e3)}}function j(){return{href:location.href,width:window.innerWidth}}function pt(d){return d.code==="unauthenticated"?"Open the review link from your invitation to send feedback.":d.code==="failed_precondition"?"Consent is needed before feedback can be sent.":"This feedback couldn't be sent."}const yt=(d,t,e)=>new lt(d,()=>B(t()),e).api();export{jt as maskedSnapshotSvg,yt as mount,G as signedIdentity,zt as uploadTarget,ht as wireContext};
|
package/package.json
CHANGED
|
@@ -1,6 +1,72 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@journeeze/sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0-rc.3",
|
|
4
|
+
"description": "Journeeze feedback mode: a tiny loader that lazy-loads the widget when the mode is switched on.",
|
|
5
|
+
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"registry": "https://registry.npmjs.org/",
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"sideEffects": [
|
|
12
|
+
"./dist/script.js"
|
|
13
|
+
],
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"LICENSE.md",
|
|
17
|
+
"CHANGELOG.md",
|
|
18
|
+
"AGENTS.md"
|
|
19
|
+
],
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/types/index.d.ts",
|
|
23
|
+
"import": "./dist/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./react": {
|
|
26
|
+
"types": "./dist/types/react.d.ts",
|
|
27
|
+
"import": "./dist/react.js"
|
|
28
|
+
},
|
|
29
|
+
"./contract": {
|
|
30
|
+
"types": "./dist/types/contract.d.ts",
|
|
31
|
+
"import": "./dist/contract.js"
|
|
32
|
+
},
|
|
33
|
+
"./script": "./dist/script.js"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"check": "tsc -p tsconfig.json",
|
|
37
|
+
"test": "vitest run",
|
|
38
|
+
"prepublishOnly": "node -e \"const fs=require('fs');for(const f of ['dist/index.js','dist/types/index.d.ts'])if(!fs.existsSync(f)){console.error('prepublishOnly: missing '+f+' - run npm run build first');process.exit(1)}\"",
|
|
39
|
+
"build": "vite build && tsc -p tsconfig.build.json && node --import tsx scripts/check-size.ts",
|
|
40
|
+
"test:e2e": "vite build && playwright install chromium && playwright test",
|
|
41
|
+
"test:e2e:real": "vite build && playwright install chromium && playwright test -c e2e/real/playwright.config.ts"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"react": ">=18",
|
|
45
|
+
"tflo-browser-events": ">=0.1.0 <1"
|
|
46
|
+
},
|
|
47
|
+
"peerDependenciesMeta": {
|
|
48
|
+
"react": {
|
|
49
|
+
"optional": true
|
|
50
|
+
},
|
|
51
|
+
"tflo-browser-events": {
|
|
52
|
+
"optional": true
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@axe-core/playwright": "^4.13.0",
|
|
57
|
+
"@babel/parser": "^7.29.9",
|
|
58
|
+
"@playwright/test": "^1.63.0",
|
|
59
|
+
"@types/react": "^19.2.0",
|
|
60
|
+
"@types/react-dom": "^19.2.0",
|
|
61
|
+
"happy-dom": "^20.0.0",
|
|
62
|
+
"magic-string": "^0.30.21",
|
|
63
|
+
"react": "^19.2.0",
|
|
64
|
+
"react-dom": "^19.2.0",
|
|
65
|
+
"tflo-browser-events": "0.3.0",
|
|
66
|
+
"tflo-browser-events-0.1.0": "npm:tflo-browser-events@0.1.0",
|
|
67
|
+
"vite": "^7.1.0"
|
|
68
|
+
},
|
|
69
|
+
"dependencies": {
|
|
70
|
+
"modern-screenshot": "4.7.0"
|
|
71
|
+
}
|
|
72
|
+
}
|