@journeeze/sdk 0.1.0-rc.2 → 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.
Files changed (72) hide show
  1. package/AGENTS.md +16 -3
  2. package/CHANGELOG.md +12 -1
  3. package/README.md +298 -119
  4. package/dist/anchor-cPvFFTOS.js +1 -0
  5. package/dist/attach-DpioALxW.js +21 -0
  6. package/dist/chat-BgmB0rnW.js +64 -0
  7. package/dist/consent-DckCUvYR.js +1 -0
  8. package/dist/contract.js +1 -1
  9. package/dist/feedback-CtH1a_kQ.js +1 -0
  10. package/dist/help-w0O5Qu-4.js +105 -0
  11. package/dist/hook-DGWypoEO.js +1 -0
  12. package/dist/index-B_nob8S0.js +1 -2091
  13. package/dist/{index-CfCbJJXa.js → index-CwG2LrhO.js} +3 -3
  14. package/dist/index.js +3 -3
  15. package/dist/jobs-CAXbM5-g.js +45 -0
  16. package/dist/loader-BZiIDD1D.js +96 -0
  17. package/dist/mask-audit-Du3NPoG_.js +5 -0
  18. package/dist/react.js +12 -11
  19. package/dist/resolve-BfWByuTp.js +1 -97
  20. package/dist/script.js +10 -9
  21. package/dist/signals-amjMQyOy.js +1 -0
  22. package/dist/telemetry-CyRJDaVs.js +1 -0
  23. package/dist/transport-B64CfIcF.js +1 -0
  24. package/dist/types/chat/capture/attach.d.ts +41 -0
  25. package/dist/types/chat/capture/draw.d.ts +10 -0
  26. package/dist/types/chat/capture/geometry.d.ts +30 -0
  27. package/dist/types/chat/capture/styles.d.ts +1 -0
  28. package/dist/types/chat/shell/chat.d.ts +27 -0
  29. package/dist/types/chat/shell/converse.d.ts +95 -0
  30. package/dist/types/chat/shell/copy.d.ts +8 -0
  31. package/dist/types/chat/shell/model.d.ts +36 -0
  32. package/dist/types/chat/shell/session.d.ts +148 -0
  33. package/dist/types/chat/shell/styles.d.ts +1 -0
  34. package/dist/types/chat/shell/view.d.ts +18 -0
  35. package/dist/types/chat/transport.d.ts +5 -0
  36. package/dist/types/config.d.ts +17 -0
  37. package/dist/types/help/core/controller.d.ts +12 -3
  38. package/dist/types/help/core/events.d.ts +24 -0
  39. package/dist/types/help/core/help.d.ts +1 -0
  40. package/dist/types/help/core/panel.d.ts +16 -0
  41. package/dist/types/help/core/routing.d.ts +21 -0
  42. package/dist/types/help/ui/jobs/jobs.d.ts +24 -0
  43. package/dist/types/help/ui/jobs/model.d.ts +33 -0
  44. package/dist/types/help/ui/jobs/styles.d.ts +1 -0
  45. package/dist/types/loader.d.ts +2 -0
  46. package/dist/types/mask-detector.d.ts +22 -0
  47. package/dist/types/preview/flag.d.ts +2 -0
  48. package/dist/types/preview/mask-audit.d.ts +29 -0
  49. package/dist/types/schemas/feedback.d.ts +76 -0
  50. package/dist/types/schemas/finding.d.ts +22 -0
  51. package/dist/types/schemas/index.d.ts +6 -0
  52. package/dist/types/schemas/turn.d.ts +26 -0
  53. package/dist/types/signals/signals.d.ts +7 -3
  54. package/dist/types/signals/steps.d.ts +33 -0
  55. package/dist/types/telemetry/telemetry.d.ts +10 -0
  56. package/dist/types/types.d.ts +72 -1
  57. package/dist/types/widget/capture.d.ts +12 -1
  58. package/dist/types/widget/upload.d.ts +14 -0
  59. package/dist/types/widget.d.ts +1 -21
  60. package/dist/upload-Fu2qvSJV.js +14 -0
  61. package/dist/widget-B6mR1J3P.js +118 -0
  62. package/package.json +4 -2
  63. package/dist/consent-CoKD33Rm.js +0 -170
  64. package/dist/feedback-C4CYtS2A.js +0 -196
  65. package/dist/help-C1x-y2f9.js +0 -878
  66. package/dist/hook-BdG4UL4k.js +0 -91
  67. package/dist/loader-Ba4X-WNl.js +0 -95
  68. package/dist/signals-E3VEdmWH.js +0 -477
  69. package/dist/telemetry-Cik-cYzw.js +0 -140
  70. package/dist/transport-B5YJFQEF.js +0 -60
  71. package/dist/types/signals/signals.conformance.d.ts +0 -2
  72. package/dist/widget-DQZm8sAC.js +0 -1599
@@ -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,6 @@
1
1
  {
2
2
  "name": "@journeeze/sdk",
3
- "version": "0.1.0-rc.2",
3
+ "version": "0.1.0-rc.3",
4
4
  "description": "Journeeze feedback mode: a tiny loader that lazy-loads the widget when the mode is switched on.",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "publishConfig": {
@@ -37,7 +37,8 @@
37
37
  "test": "vitest run",
38
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
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"
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"
41
42
  },
42
43
  "peerDependencies": {
43
44
  "react": ">=18",
@@ -52,6 +53,7 @@
52
53
  }
53
54
  },
54
55
  "devDependencies": {
56
+ "@axe-core/playwright": "^4.13.0",
55
57
  "@babel/parser": "^7.29.9",
56
58
  "@playwright/test": "^1.63.0",
57
59
  "@types/react": "^19.2.0",
@@ -1,170 +0,0 @@
1
- var g = Object.defineProperty;
2
- var T = (e, t, n) => t in e ? g(e, t, { enumerable: !0, configurable: !0, writable: !0, value: n }) : e[t] = n;
3
- var u = (e, t, n) => T(e, typeof t != "symbol" ? t + "" : t, n);
4
- import { CONTEXT_FIELDS as w, CONTEXT_VALUE_MAX_LEN as S, CONTEXT_ID_PATTERN as N, API_PATH_PATTERN as _ } from "./contract.js";
5
- import { p as E } from "./context-UnG6_X61.js";
6
- import { w as c } from "./loader-Ba4X-WNl.js";
7
- class m extends Error {
8
- constructor(n, o, r = 0, i) {
9
- super(o);
10
- u(this, "code");
11
- u(this, "status");
12
- u(this, "retryAfterMs");
13
- this.code = n, this.status = r, this.retryAfterMs = i;
14
- }
15
- }
16
- const C = "https://app.journeeze.dev", b = 15e3;
17
- function k(e, t = b) {
18
- return typeof AbortSignal < "u" && typeof AbortSignal.timeout == "function" ? { ...e, signal: AbortSignal.timeout(t) } : e;
19
- }
20
- function O(e, t = location.href) {
21
- try {
22
- return new URL(e, t).origin !== new URL(t).origin;
23
- } catch {
24
- return !0;
25
- }
26
- }
27
- const $ = "text/plain;charset=UTF-8";
28
- function A(e, t) {
29
- return `${e.replace(/\/+$/, "")}/journeeze.collector.v1.CollectorService/${t}`;
30
- }
31
- function I(e, t) {
32
- const n = O(e) ? { "content-type": $ } : { "content-type": "application/json", "connect-protocol-version": "1" };
33
- return t ? { ...n, "if-none-match": t } : n;
34
- }
35
- function y(e, t, n, o, r) {
36
- const i = k({
37
- method: "POST",
38
- headers: I(e, r.etag),
39
- body: JSON.stringify(n),
40
- credentials: "omit",
41
- cache: "no-store",
42
- referrerPolicy: "no-referrer",
43
- ...r.keepalive ? { keepalive: !0 } : {}
44
- });
45
- return o(A(e, t), i);
46
- }
47
- const j = 6e4;
48
- function M(e, t = Date.now()) {
49
- if (!e) return;
50
- const n = Number(e.trim()), o = Number.isFinite(n) && /^\d+$/.test(e.trim()) ? n * 1e3 : Date.parse(e) - t;
51
- return Number.isFinite(o) ? Math.min(Math.max(o, 0), j) : void 0;
52
- }
53
- async function v(e) {
54
- const t = await e.json().catch(() => {
55
- });
56
- if (!e.ok) {
57
- const n = typeof t?.code == "string" ? t.code : P(e.status);
58
- throw new m(n, String(t?.message ?? e.statusText), e.status, M(e.headers.get("retry-after")));
59
- }
60
- if (t === void 0 || typeof t != "object" || t === null)
61
- throw new m("unavailable", "the collector did not answer with Connect JSON", e.status);
62
- return t;
63
- }
64
- async function F(e, t, n, o = fetch, r = {}) {
65
- return v(await y(e, t, n, o, r.keepalive ? { keepalive: !0 } : {}));
66
- }
67
- async function H(e, t, n, o, r = fetch) {
68
- const i = await y(e, t, n, r, o ? { etag: o } : {});
69
- if (i.status === 304) return { notModified: !0 };
70
- const s = await v(i), a = i.headers.get("etag");
71
- return a ? { notModified: !1, value: s, etag: a } : { notModified: !1, value: s };
72
- }
73
- function X(e, t) {
74
- return t ? `${e.replace(/\/+$/, "")}${t.startsWith("/") ? "" : "/"}${t}` : void 0;
75
- }
76
- function P(e) {
77
- return e === 401 ? "unauthenticated" : e === 403 ? "permission_denied" : e === 409 ? "already_exists" : e === 412 ? "failed_precondition" : e === 429 ? "resource_exhausted" : e === 404 || e === 408 || e >= 500 ? "unavailable" : e >= 400 ? "invalid_argument" : "unknown";
78
- }
79
- function J(e, t = location.href) {
80
- const { endpoint: n, apiHost: o, apiPath: r } = e;
81
- if (n !== void 0)
82
- return c("endpoint is deprecated; use apiHost"), new URL(n, t).href.replace(/\/+$/, "");
83
- let i = C;
84
- if (o !== void 0) {
85
- const s = o.replace(/\/$/, "");
86
- let a = !1;
87
- try {
88
- const f = new URL(s);
89
- a = f.origin === s && (f.protocol === "https:" || /^(localhost|127\.0\.0\.1)$/.test(f.hostname));
90
- } catch {
91
- }
92
- a ? i = s : c("invalid apiHost ignored");
93
- }
94
- return r === void 0 ? i : _.test(r) ? i + r : (c("invalid apiPath ignored"), i);
95
- }
96
- function z(e) {
97
- const t = {};
98
- for (const n of w) {
99
- if (!(n in e)) continue;
100
- const o = e[n] || void 0;
101
- if (o !== void 0 && (typeof o != "string" || o.length > S || /[\0-\x1f\x7f]/.test(o))) {
102
- c(`context.${n} dropped (1..=128 printable characters)`), t[n] = void 0;
103
- continue;
104
- }
105
- o !== void 0 && !N.test(o) && c(`context.${n} should be an id`), t[n] = o;
106
- }
107
- return t;
108
- }
109
- const R = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$|[0-9a-f]{16}|@|^[\w-]{24,}$/i;
110
- function Y(e) {
111
- return E(e).split("/").map((t) => {
112
- let n = t;
113
- try {
114
- n = decodeURIComponent(t);
115
- } catch {
116
- }
117
- return R.test(n) ? ":id" : t;
118
- }).join("/");
119
- }
120
- const d = 1, q = "Feedback mode captures the element you point at, a screenshot of this page with form fields hidden, your comment, and your persona and journey step. It never records keystrokes, form contents or query strings. Your feedback is visible to the project's review team.", V = "Feedback mode captures the element you point at, your comment, and your persona and journey step. No screenshot is sent. It never records keystrokes, form contents or query strings. Your feedback is visible to the project's review team.", l = (e) => `jz:consent:v${d}:${e}`, p = /* @__PURE__ */ new Set(), B = (e) => e.userId ? `${e.siteKey}:u:${e.userId}` : e.siteKey;
121
- function G(e, t = h()) {
122
- p.delete(e);
123
- try {
124
- t?.removeItem(l(e));
125
- } catch {
126
- }
127
- }
128
- function h() {
129
- try {
130
- return window.localStorage;
131
- } catch {
132
- return;
133
- }
134
- }
135
- function K(e, t = h()) {
136
- if (p.has(e)) return !0;
137
- try {
138
- const n = t?.getItem(l(e));
139
- return n ? JSON.parse(n).v === d : !1;
140
- } catch {
141
- return !1;
142
- }
143
- }
144
- function W(e, t = h()) {
145
- p.add(e);
146
- try {
147
- t?.setItem(l(e), JSON.stringify({ v: d, at: (/* @__PURE__ */ new Date()).toISOString() }));
148
- } catch {
149
- }
150
- }
151
- export {
152
- m as C,
153
- q as D,
154
- j as R,
155
- $ as T,
156
- G as a,
157
- J as b,
158
- F as c,
159
- z as d,
160
- Y as e,
161
- B as f,
162
- V as g,
163
- K as h,
164
- W as i,
165
- H as j,
166
- X as k,
167
- A as r,
168
- h as s,
169
- k as w
170
- };
@@ -1,196 +0,0 @@
1
- var E = Object.defineProperty;
2
- var I = (s, e, t) => e in s ? E(s, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[e] = t;
3
- var d = (s, e, t) => I(s, typeof e != "symbol" ? e + "" : e, t);
4
- import { C as w, s as v, c as f, a as _, b as q } from "./consent-CoKD33Rm.js";
5
- const x = /* @__PURE__ */ new Set(["invalid_argument", "failed_precondition", "permission_denied", "unauthenticated", "not_found", "already_exists", "unimplemented"]), g = 50, A = 1e3, O = 6e4, y = 1440 * 60 * 1e3;
6
- function T(s) {
7
- return Math.min(O, A * 2 ** Math.max(0, s));
8
- }
9
- function L(s) {
10
- return s instanceof w && x.has(s.code);
11
- }
12
- class M {
13
- constructor(e) {
14
- d(this, "deps");
15
- d(this, "items", []);
16
- d(this, "inFlight");
17
- d(this, "attempt", 0);
18
- d(this, "flushing");
19
- d(this, "timer");
20
- d(this, "disposed", !1);
21
- d(this, "schedule");
22
- d(this, "cancel");
23
- d(this, "now");
24
- this.deps = e, this.schedule = e.schedule ?? ((t, i) => setTimeout(t, i)), this.cancel = e.cancel ?? ((t) => clearTimeout(t)), this.now = e.now ?? Date.now, this.claim();
25
- }
26
- get size() {
27
- return this.items.length;
28
- }
29
- enqueue(e) {
30
- return new Promise((t) => {
31
- const i = { request: e, settle: t };
32
- this.add(i), this.flush().then(() => {
33
- this.items.includes(i) && u(i, "queued");
34
- });
35
- });
36
- }
37
- stash(e) {
38
- this.add({ request: e });
39
- }
40
- flush() {
41
- return this.disposed ? Promise.resolve() : (this.timer !== void 0 && (this.cancel(this.timer), this.timer = void 0), this.flushing ? this.flushing.then(() => this.timer === void 0 ? this.flush() : void 0) : (this.flushing = this.drain().finally(() => {
42
- this.flushing = void 0;
43
- }), this.flushing));
44
- }
45
- persist() {
46
- const e = this.items.filter((t) => t !== this.inFlight);
47
- if (!(e.length === 0 || !this.deps.storage))
48
- try {
49
- const t = this.read(), i = this.now(), n = this.deps.user?.(), c = [...t, ...e.map((r) => ({ owner: this.deps.owner, request: r.request, at: r.at ?? i, ...n ? { user: n } : {} }))].slice(-g);
50
- this.deps.storage?.setItem(this.deps.storageKey, JSON.stringify(c));
51
- for (const r of e) u(r, "queued");
52
- this.items = this.items.filter((r) => r === this.inFlight);
53
- } catch {
54
- }
55
- }
56
- claim() {
57
- try {
58
- const e = this.read(), t = e.filter((n) => n.owner === this.deps.owner);
59
- if (t.length === 0) return;
60
- const i = e.filter((n) => n.owner !== this.deps.owner);
61
- i.length === 0 ? this.deps.storage?.removeItem(this.deps.storageKey) : this.deps.storage?.setItem(this.deps.storageKey, JSON.stringify(i));
62
- for (const n of t) this.fresh(n) && this.add({ request: n.request, at: n.at });
63
- } catch {
64
- }
65
- }
66
- dispose() {
67
- this.persist(), this.disposed = !0, this.timer !== void 0 && this.cancel(this.timer), this.timer = void 0;
68
- }
69
- add(e) {
70
- var t;
71
- for ((t = e.request).submissionId ?? (t.submissionId = F()), this.items.push(e); this.items.length > g; ) {
72
- const i = this.items[0] === this.inFlight ? 1 : 0, [n] = this.items.splice(i, 1);
73
- n && u(n, "dropped");
74
- }
75
- }
76
- async drain() {
77
- for (; !this.disposed; ) {
78
- const e = this.items[0];
79
- if (!e) {
80
- this.attempt = 0;
81
- return;
82
- }
83
- this.inFlight = e;
84
- try {
85
- await this.deps.send(e.request), this.remove(e), this.attempt = 0, u(e, "sent");
86
- } catch (t) {
87
- if (L(t)) {
88
- this.remove(e), u(e, "dropped"), this.deps.onDropped?.(t);
89
- continue;
90
- }
91
- if (this.disposed) {
92
- this.inFlight = void 0, this.persist();
93
- return;
94
- }
95
- const i = T(this.attempt++);
96
- this.timer = this.schedule(() => {
97
- this.timer = void 0, this.flush();
98
- }, i);
99
- return;
100
- } finally {
101
- this.inFlight = void 0;
102
- }
103
- }
104
- }
105
- fresh(e) {
106
- return e.at === void 0 ? !0 : typeof e.at == "number" && Number.isFinite(e.at) && this.now() - e.at <= y;
107
- }
108
- remove(e) {
109
- const t = this.items.indexOf(e);
110
- t >= 0 && this.items.splice(t, 1);
111
- }
112
- read() {
113
- const e = this.deps.storage?.getItem(this.deps.storageKey), t = e ? JSON.parse(e) : [];
114
- return Array.isArray(t) ? t.filter(
115
- (i) => typeof i == "object" && i !== null && typeof i.owner == "string" && typeof i.request == "object" && i.request !== null
116
- ) : [];
117
- }
118
- }
119
- function D(s) {
120
- if (!s) return "";
121
- let e = 2166136261;
122
- for (let t = 0; t < s.length; t++)
123
- e ^= s.charCodeAt(t), e = Math.imul(e, 16777619) >>> 0;
124
- return e.toString(16).padStart(8, "0");
125
- }
126
- function F() {
127
- return crypto.randomUUID();
128
- }
129
- function u(s, e) {
130
- const t = s.settle;
131
- s.settle = void 0, t?.(e);
132
- }
133
- function P(s, e, t, i = Date.now()) {
134
- try {
135
- const n = s?.getItem(e), c = n ? JSON.parse(n) : [], r = Array.isArray(c) ? c : [], a = r.filter((o) => o?.owner === t), h = r.filter((o) => o?.owner !== t);
136
- return h.length === 0 ? s?.removeItem(e) : s?.setItem(e, JSON.stringify(h)), a.filter((o) => o.request && (o.at === void 0 || i - o.at <= y)).sort((o, l) => (o.at ?? 0) - (l.at ?? 0)).map((o) => o.request);
137
- } catch {
138
- return [];
139
- }
140
- }
141
- const b = (s) => D(s.reviewerToken || (s.userId ? `u:${s.userId}` : void 0)), N = 32 * 1024;
142
- async function k(s) {
143
- const e = P(v(), `jz:outbox:v2:${s.siteKey}`, b(s));
144
- if (_(s.siteKey), e.length === 0) return;
145
- const t = q(s);
146
- let i = N;
147
- const n = (a, h) => f(t, "SubmitFeedback", a, fetch, { keepalive: h }), r = (await Promise.allSettled(
148
- e.map((a) => {
149
- const h = S(s, a), o = new Blob([JSON.stringify(h)]).size, l = o <= i;
150
- l && (i -= o);
151
- const m = n(h, l);
152
- return l ? m.catch((p) => p instanceof w ? Promise.reject(p) : n(h, !1)) : m;
153
- })
154
- )).filter((a) => a.status === "rejected").length;
155
- r && console.warn(`[journeeze] ${r} feedback item(s) could not be sent at logout and were discarded`);
156
- }
157
- function S(s, e) {
158
- const t = s.reviewerToken ? { ...e, reviewerToken: s.reviewerToken } : { ...e };
159
- if (s.pagePath === "none") {
160
- const { pagePath: i, ...n } = t.context;
161
- t.context = n;
162
- }
163
- return t;
164
- }
165
- function K(s, e, t = {}) {
166
- const i = (h) => f(e, "SubmitFeedback", S(s, h), fetch, { keepalive: !0 }).then(() => {
167
- }), n = new M({
168
- send: i,
169
- storage: t.memoryOnly ? void 0 : v(),
170
- storageKey: `jz:outbox:v2:${s.siteKey}`,
171
- owner: b(s),
172
- user: () => s.userId,
173
- ...t.onDropped ? { onDropped: t.onDropped } : {}
174
- }), c = () => {
175
- n.flush();
176
- }, r = () => {
177
- t.beforePersist?.(), n.persist();
178
- }, a = (h) => {
179
- h.persisted && (n.claim(), n.flush());
180
- };
181
- return window.addEventListener("online", c), window.addEventListener("pagehide", r), window.addEventListener("pageshow", a), {
182
- outbox: n,
183
- dispose() {
184
- window.removeEventListener("online", c), window.removeEventListener("pagehide", r), window.removeEventListener("pageshow", a), n.dispose();
185
- }
186
- };
187
- }
188
- function z(s, e) {
189
- return f(s, "GetWidgetConfig", { siteKey: e });
190
- }
191
- export {
192
- K as feedbackChannel,
193
- k as logout,
194
- b as ownerOf,
195
- z as widgetConfig
196
- };