@holdyapp/sdk 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +165 -0
  3. package/dist/anchor.d.ts +8 -0
  4. package/dist/auto-capture.d.ts +21 -0
  5. package/dist/holdy.cjs.js +255 -0
  6. package/dist/holdy.cjs.js.map +7 -0
  7. package/dist/holdy.esm.js +255 -0
  8. package/dist/holdy.esm.js.map +7 -0
  9. package/dist/holdy.iife.js +255 -0
  10. package/dist/holdy.iife.js.map +7 -0
  11. package/dist/index.d.ts +46 -0
  12. package/dist/outcome.d.ts +19 -0
  13. package/dist/queue.d.ts +54 -0
  14. package/dist/render/kinds/banner.d.ts +3 -0
  15. package/dist/render/kinds/checklist.d.ts +19 -0
  16. package/dist/render/kinds/cta.d.ts +8 -0
  17. package/dist/render/kinds/modal.d.ts +16 -0
  18. package/dist/render/kinds/shared.d.ts +16 -0
  19. package/dist/render/kinds/spotlight.d.ts +17 -0
  20. package/dist/render/kinds/tooltip.d.ts +3 -0
  21. package/dist/render/root.d.ts +3 -0
  22. package/dist/render/styles.d.ts +5 -0
  23. package/dist/store.d.ts +36 -0
  24. package/dist/transport.d.ts +59 -0
  25. package/dist/types.d.ts +114 -0
  26. package/package.json +60 -0
  27. package/src/anchor.ts +72 -0
  28. package/src/auto-capture.ts +129 -0
  29. package/src/index.ts +427 -0
  30. package/src/outcome.ts +51 -0
  31. package/src/queue.ts +296 -0
  32. package/src/render/kinds/banner.ts +52 -0
  33. package/src/render/kinds/checklist.ts +175 -0
  34. package/src/render/kinds/cta.ts +53 -0
  35. package/src/render/kinds/modal.ts +129 -0
  36. package/src/render/kinds/shared.ts +67 -0
  37. package/src/render/kinds/spotlight.ts +176 -0
  38. package/src/render/kinds/tooltip.ts +82 -0
  39. package/src/render/root.ts +69 -0
  40. package/src/render/styles.ts +280 -0
  41. package/src/store.ts +106 -0
  42. package/src/transport.ts +182 -0
  43. package/src/types.ts +173 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Holdy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,165 @@
1
+ # @holdyapp/sdk
2
+
3
+ Holdy SDK · behavioral telemetry + in-product interventions for B2B SaaS Customer Success.
4
+
5
+ **< 15kb gzipped.** Sem dependências runtime. ESM + CJS + IIFE builds.
6
+
7
+ ---
8
+
9
+ ## Instalação rápida
10
+
11
+ ### Opção 1 · `npx` (recomendado · 1 minuto)
12
+
13
+ ```bash
14
+ npx @holdyapp/install <SUA_API_KEY>
15
+ ```
16
+
17
+ Detecta seu framework (Next.js, Vite, Vue, Nuxt, vanilla HTML) e injeta o snippet no lugar certo.
18
+
19
+ ### Opção 2 · Script tag (CDN)
20
+
21
+ ```html
22
+ <script src="https://app.holdy.com.br/sdk/v0/holdy.iife.js"></script>
23
+ <script>
24
+ Holdy.init({
25
+ apiKey: 'hol_live_xxxxxxxx',
26
+ accountId: 'acme-corp',
27
+ autoCapture: true,
28
+ })
29
+ </script>
30
+ ```
31
+
32
+ ### Opção 3 · npm + ES module
33
+
34
+ ```bash
35
+ npm install @holdyapp/sdk
36
+ ```
37
+
38
+ ```ts
39
+ import { Holdy } from '@holdyapp/sdk'
40
+
41
+ Holdy.init({
42
+ apiKey: 'hol_live_xxxxxxxx',
43
+ accountId: 'acme-corp',
44
+ autoCapture: true,
45
+ })
46
+ ```
47
+
48
+ ---
49
+
50
+ ## Identify rico
51
+
52
+ Holdy nunca sobrescreve dados preenchidos no wizard — sempre `COALESCE`. Você pode chamar `identify()` várias vezes; backend só preenche campos vazios.
53
+
54
+ ```ts
55
+ Holdy.identify({
56
+ account: {
57
+ external_id: 'acct_123',
58
+ name: 'Acme Corp',
59
+ logo_url: 'https://acme.com/logo.png',
60
+ plan: 'Enterprise',
61
+ mrr: 5000,
62
+ },
63
+ user: {
64
+ external_id: 'user_456',
65
+ email: 'ceo@acme.com',
66
+ name: 'John Doe',
67
+ role: 'decision_maker',
68
+ },
69
+ })
70
+ ```
71
+
72
+ ---
73
+
74
+ ## Track manual (eventos canônicos)
75
+
76
+ 20 primitives semânticos validados por taxonomia v1. Lista completa em https://app.holdy.com.br/api/v1/docs.
77
+
78
+ ```ts
79
+ // Workflow bloqueado · um dos sinais mais úteis pro motor de decisão
80
+ Holdy.track('workflow.blocked', {
81
+ workflow: 'invoice-export',
82
+ reason: 'permission_denied',
83
+ severity: 'high',
84
+ })
85
+
86
+ // Fricção detectada (rage clicks, retry loop, etc)
87
+ Holdy.track('friction.detected', {
88
+ signal: 'rage_click',
89
+ surface: '/billing',
90
+ })
91
+
92
+ // Sinal de expansão
93
+ Holdy.track('expansion.intent_detected', {
94
+ workflow: 'pricing-page-view',
95
+ evidence: 'visited 3x in 7d',
96
+ })
97
+ ```
98
+
99
+ ---
100
+
101
+ ## Auto-capture (sem código)
102
+
103
+ Quando `autoCapture: true` (recomendado em desenvolvimento e produção), o SDK monitora navegação do SPA automaticamente:
104
+
105
+ - Carregamento inicial da página
106
+ - `pushState` / `replaceState` (Next.js, React Router, Vue Router)
107
+ - `popstate` (botão voltar)
108
+
109
+ Cada navegação gera `memory.append` com `{kind: 'route', path, title, referrer}`. Você vê dados no Holdy assim que o cliente carregar a página — sem precisar instrumentar nada manualmente.
110
+
111
+ Track manual continua disponível para os sinais semânticos (workflow/friction/expansion/outcome) que o auto-capture não pode adivinhar.
112
+
113
+ ---
114
+
115
+ ## Render in-product
116
+
117
+ Quando o backend de decisão sugere uma intervenção (tooltip, banner, modal, checklist, spotlight, CTA), o SDK renderiza automaticamente. Desabilitar:
118
+
119
+ ```ts
120
+ Holdy.init({
121
+ apiKey: '...',
122
+ renderInterventions: false, // SDK só captura, não renderiza nada
123
+ })
124
+ ```
125
+
126
+ ---
127
+
128
+ ## Reportar outcome
129
+
130
+ ```ts
131
+ Holdy.onDecision((decision) => {
132
+ // ... seu código pode reagir
133
+ })
134
+
135
+ // Após o user agir em consequência:
136
+ Holdy.reportOutcome(decisionId, 'converted', { value: 99 })
137
+ ```
138
+
139
+ ---
140
+
141
+ ## Configuração completa
142
+
143
+ ```ts
144
+ interface HoldyConfig {
145
+ apiKey: string // hol_live_… ou hol_test_…
146
+ apiUrl?: string // default: https://app.holdy.com.br/api/v1
147
+ accountId?: string // ID Holdy ou external_id (use identify pra rico)
148
+ userId?: string
149
+ sessionId?: string
150
+ consumer?: 'ui' | 'csm' | 'agent'
151
+ debug?: boolean // console.warn em erros
152
+ renderInterventions?: boolean // default: true
153
+ autoCapture?: boolean // default: false · auto page.view tracking
154
+ }
155
+ ```
156
+
157
+ ---
158
+
159
+ ## Tamanho
160
+
161
+ Bundle IIFE gzip < 15kb (budget enforced no build).
162
+
163
+ ## Licença
164
+
165
+ MIT
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Anchor resolver · MutationObserver-based.
3
+ *
4
+ * Cliente do produto pode renderizar o anchor depois do decision chegar
5
+ * (SPA route, lazy mount). Resolver espera até 5s antes de desistir.
6
+ * Single observer global · cap retries por selector.
7
+ */
8
+ export declare function resolveAnchor(selector: string | undefined): Promise<Element | null>;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Auto-capture · Stage 28 G_auto.
3
+ *
4
+ * Quando HoldyConfig.autoCapture=true, instalamos hooks globais que
5
+ * emitem `session.activity` automaticamente:
6
+ *
7
+ * · initial_load · 1x ao init
8
+ * · route_change · cada history.pushState/replaceState/popstate
9
+ * · visibility_change · página voltou a ficar visível
10
+ *
11
+ * Tudo client-side · não precisa que o customer declare nada. Permite que
12
+ * o widget de install do Holdy mostre "✓ conectado" segundos após o user
13
+ * carregar a página.
14
+ *
15
+ * Idempotente · re-rodar `installAutoCapture` é no-op via guard global.
16
+ * Cleanup ao destroy via array de unsubscribers retornado.
17
+ */
18
+ export interface AutoCaptureEmit {
19
+ (path: string, title: string | undefined, referrer: string | undefined, kind: 'initial_load' | 'route_change' | 'visibility_change'): void;
20
+ }
21
+ export declare function installAutoCapture(emit: AutoCaptureEmit): () => void;
@@ -0,0 +1,255 @@
1
+ "use strict";var $=Object.defineProperty;var ye=Object.getOwnPropertyDescriptor;var ge=Object.getOwnPropertyNames;var ve=Object.prototype.hasOwnProperty;var we=(i,e)=>{for(var t in e)$(i,t,{get:e[t],enumerable:!0})},be=(i,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of ge(e))!ve.call(i,o)&&o!==t&&$(i,o,{get:()=>e[o],enumerable:!(n=ye(e,o))||n.enumerable});return i};var _e=i=>be($({},"__esModule",{value:!0}),i);var Be={};we(Be,{Holdy:()=>me,default:()=>Oe});module.exports=_e(Be);var xe="holdy_sdk_v1",O="event_queue";function ke(){return typeof indexedDB!="undefined"}var D=null;function Ee(){return D||(D=new Promise((i,e)=>{let t=indexedDB.open(xe,1);t.onupgradeneeded=()=>{let n=t.result;n.objectStoreNames.contains(O)||n.createObjectStore(O,{keyPath:"id",autoIncrement:!0})},t.onsuccess=()=>i(t.result),t.onerror=()=>e(t.error)}),D)}function R(i,e){return Ee().then(t=>new Promise((n,o)=>{let r=t.transaction(O,i),s=r.objectStore(O),d;try{let l=e(s);l instanceof IDBRequest?(l.onsuccess=()=>{d=l.result},l.onerror=()=>o(l.error)):l.then(y=>d=y)}catch(l){o(l);return}r.oncomplete=()=>n(d),r.onerror=()=>o(r.error),r.onabort=()=>o(r.error)}))}var Ce={async add(i){await R("readwrite",e=>e.add(i))},async pickDue(i,e){let t=await R("readonly",n=>n.getAll());return(t!=null?t:[]).filter(n=>n.next_retry_at<=i).sort((n,o)=>n.next_retry_at-o.next_retry_at).slice(0,e)},async update(i){await R("readwrite",e=>e.put(i))},async remove(i){await R("readwrite",e=>e.delete(i))},async count(){return R("readonly",i=>i.count())},async dropOldest(i){let e=await R("readonly",n=>n.getAll()),t=(e!=null?e:[]).sort((n,o)=>n.created_at-o.created_at).slice(0,i);for(let n of t)n.id!==void 0&&await R("readwrite",o=>o.delete(n.id))},async all(){var i;return(i=await R("readonly",e=>e.getAll()))!=null?i:[]}},z=class{constructor(){this.items=[];this.nextId=1}async add(e){this.items.push({...e,id:this.nextId++})}async pickDue(e,t){return this.items.filter(n=>n.next_retry_at<=e).sort((n,o)=>n.next_retry_at-o.next_retry_at).slice(0,t)}async update(e){let t=this.items.findIndex(n=>n.id===e.id);t>=0&&(this.items[t]=e)}async remove(e){this.items=this.items.filter(t=>t.id!==e)}async count(){return this.items.length}async dropOldest(e){this.items.sort((t,n)=>t.created_at-n.created_at),this.items.splice(0,e)}async all(){return[...this.items]}},B=class{constructor(e,t=()=>{}){this.flushTimer=null;this.flushing=!1;this.driver=ke()?Ce:new z,this.send=e,this.log=t,this.startFlusher(),this.bindPagehide()}async enqueue(e){if(e.length===0)return;let t=await this.driver.count().catch(()=>0);if(t===0&&await this.send({events:e}).catch(()=>!1))return;if(t>=1e3){let o=t-1e3+1;await this.driver.dropOldest(o).catch(()=>{}),this.log("queue full \xB7 dropped",o,"oldest batches")}let n=Date.now();await this.driver.add({events:e,attempts:0,next_retry_at:n+1e3,created_at:n}).catch(o=>this.log("queue add failed",o))}startFlusher(){this.flushTimer||typeof setInterval!="undefined"&&(this.flushTimer=setInterval(()=>{this.flushOnce()},5e3))}async flushOnce(){if(!this.flushing){this.flushing=!0;try{let e=Date.now(),t=await this.driver.pickDue(e,10).catch(()=>[]);for(let n of t){if(await this.send({events:n.events}).catch(()=>!1)&&n.id!==void 0){await this.driver.remove(n.id).catch(()=>{});continue}let r=n.attempts+1;if(r>=5){n.id!==void 0&&await this.driver.remove(n.id).catch(()=>{}),this.log("dropped batch after max attempts",{events:n.events.length});continue}let s=1e3*Math.pow(2,r);await this.driver.update({...n,attempts:r,next_retry_at:Date.now()+s}).catch(()=>{})}}finally{this.flushing=!1}}}bindPagehide(){if(typeof window=="undefined")return;let e=()=>{this.driver.all().then(t=>{for(let n of t)this.send({events:n.events}).catch(()=>{})}).catch(()=>{})};window.addEventListener("pagehide",e),window.addEventListener("beforeunload",e)}destroy(){this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=null)}};var Te="https://app.holdy.com.br/api/v1",H=class{constructor(e){var t,n;this.apiKey=e.apiKey,this.apiUrl=((t=e.apiUrl)!=null?t:Te).replace(/\/$/,""),this.debug=(n=e.debug)!=null?n:!1,this.queue=new B(o=>this.sendBatch(o.events),(...o)=>this.log(...o))}headers(){return{"content-type":"application/json",authorization:`Bearer ${this.apiKey}`}}async fetchRuntimeConfig(){try{let e=await fetch(`${this.apiUrl}/runtime/config`,{method:"GET",headers:this.headers(),credentials:"omit",mode:"cors"});return e.ok?await e.json():(this.log("runtime/config failed",e.status),null)}catch(e){return this.log("runtime/config error",e),null}}async evaluate(e){try{let t=await fetch(`${this.apiUrl}/decisions/evaluate`,{method:"POST",headers:this.headers(),body:JSON.stringify({consumer:"ui",...e}),credentials:"omit",mode:"cors"});return t.ok?await t.json():(this.log("decisions/evaluate failed",t.status),null)}catch(t){return this.log("decisions/evaluate error",t),null}}ingestBatch(e){e.length!==0&&this.queue.enqueue(e)}async sendBatch(e){try{return(await fetch(`${this.apiUrl}/events/batch`,{method:"POST",headers:this.headers(),body:JSON.stringify({events:e}),credentials:"omit",mode:"cors",keepalive:!0})).ok}catch(t){return this.log("events/batch network error",t),!1}}async upsertAccount(e){try{let t=await fetch(`${this.apiUrl}/accounts/upsert`,{method:"POST",headers:this.headers(),body:JSON.stringify(e),credentials:"omit",mode:"cors",keepalive:!0});return t.ok?await t.json():(this.log("accounts/upsert failed",t.status),null)}catch(t){return this.log("accounts/upsert error",t),null}}reportOutcome(e,t,n){let o=`${this.apiUrl}/decisions/${encodeURIComponent(e)}/outcome`;fetch(o,{method:"POST",headers:this.headers(),body:JSON.stringify({outcome:t,metadata:n}),credentials:"omit",mode:"cors",keepalive:!0}).catch(r=>this.log("decisions/outcome error",r))}log(...e){this.debug&&typeof console!="undefined"&&console.warn("[holdy]",...e)}destroy(){this.queue.destroy()}};var M=class{constructor(e){this.pending=new Map;this.transport=e}registerPending(e,t){this.pending.set(e,{id:e,workflow:t,startedAt:Date.now()})}dispatch(e,t,n){var o,r,s;if(!this.pending.has(e)&&t!=="failed"){this.transport.reportOutcome(e,t,n);return}this.pending.delete(e),this.transport.reportOutcome(e,t,{...n,latency_ms:(s=n==null?void 0:n.latency_ms)!=null?s:Date.now()-((r=(o=this.pending.get(e))==null?void 0:o.startedAt)!=null?r:Date.now())})}hasPending(e){return this.pending.has(e)}};var N=class{constructor(){this.tooltipsByAnchor=new Map;this.spotlightsByAnchor=new Map;this.banner=null;this.modal=null;this.checklist=null;this.cta=null}claim(e,t,n,o,r){let s={decisionId:t,confidence:n,kind:e,dismiss:r};if(e==="tooltip"){let d=o!=null?o:"__no_anchor__",l=this.tooltipsByAnchor.get(d);return l&&l.confidence>=n?s:(this.tooltipsByAnchor.set(d,s),l!=null?l:null)}if(e==="spotlight"){let d=o!=null?o:"__no_anchor__",l=this.spotlightsByAnchor.get(d);return l&&l.confidence>=n?s:(this.spotlightsByAnchor.set(d,s),l!=null?l:null)}if(e==="banner"){let d=this.banner;return d&&d.confidence>=n?s:(this.banner=s,d!=null?d:null)}if(e==="modal"){let d=this.modal;return d&&d.confidence>=n?s:(this.modal=s,d!=null?d:null)}if(e==="checklist"){let d=this.checklist;return d&&d.confidence>=n?s:(this.checklist=s,d!=null?d:null)}if(e==="cta"){let d=this.cta;return d&&d.confidence>=n?s:(this.cta=s,d!=null?d:null)}return null}release(e){var t,n,o,r;((t=this.banner)==null?void 0:t.decisionId)===e&&(this.banner=null),((n=this.modal)==null?void 0:n.decisionId)===e&&(this.modal=null),((o=this.checklist)==null?void 0:o.decisionId)===e&&(this.checklist=null),((r=this.cta)==null?void 0:r.decisionId)===e&&(this.cta=null);for(let s of[this.tooltipsByAnchor,this.spotlightsByAnchor])for(let[d,l]of s)if(l.decisionId===e){s.delete(d);break}}};var I=new Set,S=null;function Re(){S||typeof MutationObserver=="undefined"||typeof document=="undefined"||(S=new MutationObserver(()=>{I.size!==0&&(I.forEach(i=>{let e=document.querySelector(i.selector);e&&(i.cleanup(),i.resolve(e))}),I.size===0&&Z())}),S.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["id","class","data-holdy-anchor"]}))}function Z(){S&&(S.disconnect(),S=null)}function q(i){if(!i||typeof document=="undefined")return Promise.resolve(null);let e=document.querySelector(i);return e?Promise.resolve(e):new Promise(t=>{let n=!1,o={selector:i,resolve:t,cleanup:()=>{n||(n=!0,I.delete(o),clearTimeout(r),I.size===0&&Z())}},r=setTimeout(()=>{o.cleanup(),t(null)},5e3);I.add(o),Re()})}var Q="__holdy_autocapture_installed__";function Y(i){if(typeof window=="undefined"||typeof history=="undefined")return()=>{};let e=window;if(e[Q])return()=>{};e[Q]=!0;let t=[],n=K(),o=null;function r(u){try{let g=K(),a=typeof document!="undefined"?document.title:void 0,h=typeof document!="undefined"&&document.referrer||void 0;i(g,a,h,u)}catch(g){}}function s(){o&&clearTimeout(o),o=setTimeout(()=>{let u=K();u!==n&&(n=u,r("route_change")),o=null},50)}r("initial_load");let d=history.pushState,l=history.replaceState;history.pushState=function(...g){let a=d.apply(this,g);return s(),a},history.replaceState=function(...g){let a=l.apply(this,g);return s(),a},t.push(()=>{history.pushState=d,history.replaceState=l});let y=()=>s();window.addEventListener("popstate",y),t.push(()=>window.removeEventListener("popstate",y));let p=()=>s();window.addEventListener("hashchange",p),t.push(()=>window.removeEventListener("hashchange",p));let v=null,f=()=>{if(typeof document!="undefined"){if(document.visibilityState==="hidden")v=Date.now();else if(document.visibilityState==="visible"&&v){let u=Date.now()-v;v=null,u>5*6e4&&r("visibility_change")}}};return typeof document!="undefined"&&(document.addEventListener("visibilitychange",f),t.push(()=>document.removeEventListener("visibilitychange",f))),()=>{o&&clearTimeout(o);for(let u of t)u();e[Q]=!1}}function K(){return typeof window=="undefined"||!window.location?"/":window.location.pathname+window.location.search+window.location.hash}var ee={primary_color:"#ca2121",font_family:"inherit",border_radius_px:8,position_offset_px:8};var te=`
2
+ :host {
3
+ --holdy-primary: var(--holdy-cfg-primary, #ca2121);
4
+ --holdy-font: var(--holdy-cfg-font, system-ui, -apple-system, sans-serif);
5
+ --holdy-radius: var(--holdy-cfg-radius, 8px);
6
+ --holdy-offset: var(--holdy-cfg-offset, 8px);
7
+ --holdy-bg: #ffffff;
8
+ --holdy-fg: #1a1a1a;
9
+ --holdy-muted: #737373;
10
+ --holdy-border: rgba(0, 0, 0, 0.08);
11
+ --holdy-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
12
+ all: initial;
13
+ font-family: var(--holdy-font);
14
+ color: var(--holdy-fg);
15
+ }
16
+
17
+ @media (prefers-color-scheme: dark) {
18
+ :host {
19
+ --holdy-bg: #111111;
20
+ --holdy-fg: #f5f5f5;
21
+ --holdy-muted: #a3a3a3;
22
+ --holdy-border: rgba(255, 255, 255, 0.12);
23
+ --holdy-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
24
+ }
25
+ }
26
+
27
+ .holdy-card {
28
+ background: var(--holdy-bg);
29
+ color: var(--holdy-fg);
30
+ border: 1px solid var(--holdy-border);
31
+ border-radius: var(--holdy-radius);
32
+ box-shadow: var(--holdy-shadow);
33
+ padding: 12px 14px;
34
+ font-size: 14px;
35
+ line-height: 1.45;
36
+ max-width: 320px;
37
+ pointer-events: auto;
38
+ }
39
+
40
+ .holdy-card-text {
41
+ margin: 0;
42
+ }
43
+
44
+ .holdy-card-actions {
45
+ display: flex;
46
+ gap: 8px;
47
+ margin-top: 10px;
48
+ align-items: center;
49
+ justify-content: flex-end;
50
+ }
51
+
52
+ .holdy-btn {
53
+ font-family: var(--holdy-font);
54
+ font-size: 13px;
55
+ font-weight: 500;
56
+ padding: 6px 12px;
57
+ border-radius: 6px;
58
+ border: none;
59
+ cursor: pointer;
60
+ background: var(--holdy-primary);
61
+ color: #ffffff;
62
+ text-decoration: none;
63
+ display: inline-flex;
64
+ align-items: center;
65
+ }
66
+
67
+ .holdy-btn:focus-visible {
68
+ outline: 2px solid var(--holdy-primary);
69
+ outline-offset: 2px;
70
+ }
71
+
72
+ .holdy-btn-ghost {
73
+ background: transparent;
74
+ color: var(--holdy-muted);
75
+ border: 1px solid var(--holdy-border);
76
+ }
77
+
78
+ .holdy-close {
79
+ background: transparent;
80
+ border: none;
81
+ color: var(--holdy-muted);
82
+ font-size: 16px;
83
+ line-height: 1;
84
+ cursor: pointer;
85
+ padding: 4px;
86
+ border-radius: 4px;
87
+ }
88
+
89
+ .holdy-close:hover {
90
+ color: var(--holdy-fg);
91
+ }
92
+
93
+ .holdy-tooltip {
94
+ position: fixed;
95
+ z-index: 2147483647;
96
+ max-width: 280px;
97
+ }
98
+
99
+ .holdy-banner {
100
+ position: fixed;
101
+ top: 0;
102
+ left: 50%;
103
+ transform: translateX(-50%);
104
+ margin-top: var(--holdy-offset);
105
+ z-index: 2147483647;
106
+ max-width: min(560px, calc(100vw - 32px));
107
+ display: flex;
108
+ align-items: center;
109
+ gap: 12px;
110
+ }
111
+
112
+ .holdy-banner .holdy-card-text {
113
+ flex: 1;
114
+ }
115
+
116
+ .holdy-cta {
117
+ position: fixed;
118
+ right: var(--holdy-offset);
119
+ bottom: var(--holdy-offset);
120
+ z-index: 2147483647;
121
+ max-width: 320px;
122
+ }
123
+
124
+ .holdy-card-title {
125
+ margin: 0 0 6px;
126
+ font-size: 15px;
127
+ font-weight: 600;
128
+ line-height: 1.3;
129
+ }
130
+
131
+ /* \u2500\u2500 Modal (Wave 2) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
132
+ .holdy-modal-backdrop {
133
+ position: fixed;
134
+ inset: 0;
135
+ background: rgba(0, 0, 0, 0.5);
136
+ display: flex;
137
+ align-items: center;
138
+ justify-content: center;
139
+ z-index: 2147483647;
140
+ padding: 20px;
141
+ pointer-events: auto;
142
+ }
143
+
144
+ .holdy-modal {
145
+ max-width: 480px;
146
+ width: 100%;
147
+ padding: 20px 22px;
148
+ }
149
+
150
+ .holdy-modal:focus {
151
+ outline: none;
152
+ }
153
+
154
+ /* \u2500\u2500 Checklist (Wave 2) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
155
+ .holdy-checklist {
156
+ position: fixed;
157
+ right: var(--holdy-offset);
158
+ bottom: var(--holdy-offset);
159
+ z-index: 2147483647;
160
+ max-width: 320px;
161
+ padding: 14px 16px;
162
+ }
163
+
164
+ .holdy-checklist-header {
165
+ display: flex;
166
+ align-items: flex-start;
167
+ justify-content: space-between;
168
+ gap: 8px;
169
+ margin-bottom: 4px;
170
+ }
171
+
172
+ .holdy-checklist-title {
173
+ margin: 0;
174
+ font-size: 14px;
175
+ font-weight: 600;
176
+ line-height: 1.3;
177
+ flex: 1;
178
+ }
179
+
180
+ .holdy-checklist-list {
181
+ list-style: none;
182
+ padding: 0;
183
+ margin: 8px 0 0;
184
+ display: flex;
185
+ flex-direction: column;
186
+ gap: 6px;
187
+ }
188
+
189
+ .holdy-checklist-item {
190
+ display: flex;
191
+ align-items: center;
192
+ gap: 8px;
193
+ font-size: 13px;
194
+ line-height: 1.4;
195
+ }
196
+
197
+ .holdy-checklist-item.is-done .holdy-checklist-label {
198
+ text-decoration: line-through;
199
+ color: var(--holdy-muted);
200
+ }
201
+
202
+ .holdy-checklist-checkbox {
203
+ accent-color: var(--holdy-primary);
204
+ cursor: pointer;
205
+ flex-shrink: 0;
206
+ }
207
+
208
+ .holdy-checklist-label {
209
+ color: var(--holdy-fg);
210
+ text-decoration: none;
211
+ cursor: pointer;
212
+ }
213
+
214
+ .holdy-checklist-label:hover {
215
+ color: var(--holdy-primary);
216
+ }
217
+
218
+ /* \u2500\u2500 Spotlight (Wave 2) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
219
+ .holdy-spotlight-container {
220
+ position: fixed;
221
+ inset: 0;
222
+ z-index: 2147483647;
223
+ pointer-events: none;
224
+ }
225
+
226
+ .holdy-spotlight-backdrop {
227
+ position: absolute;
228
+ inset: 0;
229
+ background: rgba(0, 0, 0, 0.55);
230
+ pointer-events: auto;
231
+ transition: clip-path 120ms ease-out;
232
+ }
233
+
234
+ .holdy-spotlight-ring {
235
+ position: absolute;
236
+ border-radius: 8px;
237
+ box-shadow: 0 0 0 2px var(--holdy-primary), 0 0 24px rgba(202, 33, 33, 0.4);
238
+ pointer-events: none;
239
+ transition: top 120ms, left 120ms, width 120ms, height 120ms;
240
+ }
241
+
242
+ .holdy-spotlight-tooltip {
243
+ position: absolute;
244
+ max-width: 320px;
245
+ pointer-events: auto;
246
+ }
247
+ `,W=null;function ne(){if(typeof CSSStyleSheet=="undefined")return null;if(W)return W;try{let i=new CSSStyleSheet;return i.replaceSync(te),W=i,i}catch(i){return null}}function V(i,e){let t=e!=null?e:ee;i.style.setProperty("--holdy-cfg-primary",t.primary_color),i.style.setProperty("--holdy-cfg-font",t.font_family),i.style.setProperty("--holdy-cfg-radius",`${t.border_radius_px}px`),i.style.setProperty("--holdy-cfg-offset",`${t.position_offset_px}px`)}function j(i){let e=document.createElement("style");e.textContent=te,i.appendChild(e)}var G="holdy-root",b=null,A=null;function Ie(){if(typeof customElements=="undefined"||customElements.get(G))return;class i extends HTMLElement{}try{customElements.define(G,i)}catch(e){}}function ie(i){if(typeof document=="undefined")return null;if(A)return b&&V(b,i),A;Ie(),b=document.createElement(G),b.setAttribute("aria-live","polite"),b.setAttribute("data-holdy-root","1"),b.style.position="fixed",b.style.top="0",b.style.left="0",b.style.width="0",b.style.height="0",b.style.zIndex="2147483647",b.style.pointerEvents="none";let e=b.attachShadow({mode:"closed"});A=e;let t=ne();if(t&&"adoptedStyleSheets"in e)try{e.adoptedStyleSheets=[t]}catch(n){j(e)}else j(e);return V(b,i),document.body?document.body.appendChild(b):document.addEventListener("DOMContentLoaded",()=>{b&&!b.isConnected&&document.body.appendChild(b)}),A}function oe(i){A&&(i.style.pointerEvents="auto",A.appendChild(i))}function k(i){let e=document.createElement("button");return e.type="button",e.className="holdy-close",e.setAttribute("aria-label","Fechar"),e.textContent="\xD7",e.addEventListener("click",t=>{t.stopPropagation(),i()}),e}function E(i,e){if(!i.cta_text)return null;let t;if(i.cta_href){let n=document.createElement("a");n.href=i.cta_href,n.rel="noopener noreferrer",n.target="_self",t=n}else t=document.createElement("button"),t.type="button";return t.className="holdy-btn",t.textContent=i.cta_text,t.addEventListener("click",()=>e()),t}function C(i){let e=document.createElement("p");return e.className="holdy-card-text",e.textContent=i,e}function T(...i){let e=i.filter(n=>n!==null);if(e.length===0)return null;let t=document.createElement("div");return t.className="holdy-card-actions",e.forEach(n=>t.appendChild(n)),t}var re=8;function se(i,e,t){let n=document.createElement("div");n.className="holdy-card holdy-tooltip",n.setAttribute("role","tooltip");let o=C(i.text);n.appendChild(o);let r=k(()=>p("dismissed")),s=E(i,()=>{t.onExecuted(),y()}),d=T(s,r);d?n.appendChild(d):n.appendChild(r);let l=!1,y=()=>{l||(l=!0,n.remove(),window.removeEventListener("scroll",v,!0),window.removeEventListener("resize",v))},p=(f="dismissed")=>{l||(f==="dismissed"&&t.onDismissed(),f==="failed"&&t.onFailed(),y())},v=()=>{if(!e)return;let f=e.getBoundingClientRect();if(f.width===0&&f.height===0)return;let u=n.getBoundingClientRect(),g=f.bottom+re,a=f.left+f.width/2-u.width/2,h=window.innerWidth-u.width-8;a<8&&(a=8),a>h&&(a=h),g+u.height>window.innerHeight-8&&(g=f.top-u.height-re),n.style.top=`${Math.max(8,g)}px`,n.style.left=`${a}px`};return n.style.top="-9999px",n.style.left="-9999px",requestAnimationFrame(()=>{v(),window.addEventListener("scroll",v,!0),window.addEventListener("resize",v)}),{el:n,dismiss:f=>p(f==="failed"||f==="no_show"?f:"dismissed")}}function de(i,e){let t=document.createElement("div");t.className="holdy-card holdy-banner",t.setAttribute("role","status");let n=C(i.text);t.appendChild(n);let o=k(()=>y("dismissed")),r=E(i,()=>{e.onExecuted(),l()}),s=T(r,o);s?(s.style.marginTop="0",t.appendChild(s)):t.appendChild(o);let d=!1,l=()=>{d||(d=!0,t.remove())},y=(p="dismissed")=>{d||(p==="dismissed"&&e.onDismissed(),p==="failed"&&e.onFailed(),l())};return{el:t,dismiss:p=>y(p==="failed"||p==="no_show"?p:"dismissed")}}function ae(i,e){let t=document.createElement("div");t.className="holdy-card holdy-cta",t.setAttribute("role","dialog"),t.setAttribute("aria-label","Sugest\xE3o Holdy");let n=C(i.text);t.appendChild(n);let o=k(()=>y("dismissed")),r=E(i,()=>{e.onExecuted(),l()}),s=T(r,o);s?t.appendChild(s):t.appendChild(o);let d=!1,l=()=>{d||(d=!0,t.remove())},y=(p="dismissed")=>{d||(p==="dismissed"&&e.onDismissed(),p==="failed"&&e.onFailed(),l())};return{el:t,dismiss:p=>y(p==="failed"||p==="no_show"?p:"dismissed")}}function le(i,e){let t=document.createElement("div");t.className="holdy-modal-backdrop";let n=document.createElement("div");if(n.className="holdy-card holdy-modal",n.setAttribute("role","dialog"),n.setAttribute("aria-modal","true"),n.tabIndex=-1,i.title){let a=document.createElement("h2");a.className="holdy-card-title",a.textContent=i.title,n.appendChild(a)}let o=C(i.text);n.appendChild(o);let r=k(()=>g("dismissed")),s=E(i,()=>{e.onExecuted(),u()}),d=T(s,r);d?n.appendChild(d):n.appendChild(r),t.appendChild(n);let l=document.body.style.overflow;document.body.style.overflow="hidden",t.addEventListener("click",a=>{a.target===t&&g("dismissed",{reason:"backdrop_click"})});let y=document.activeElement;(()=>{requestAnimationFrame(()=>{let a=n.querySelector('a, button, [tabindex]:not([tabindex="-1"])');(a!=null?a:n).focus()})})();let v=a=>{if(a.key==="Escape"){a.stopPropagation(),g("dismissed",{reason:"esc"});return}if(a.key!=="Tab")return;let h=Array.from(n.querySelectorAll('a, button, [tabindex]:not([tabindex="-1"])'));if(h.length===0)return;let m=h[0],c=h[h.length-1],w=document.activeElement;a.shiftKey&&w===m?(a.preventDefault(),c.focus()):!a.shiftKey&&w===c&&(a.preventDefault(),m.focus())};document.addEventListener("keydown",v,!0);let f=!1,u=()=>{f||(f=!0,document.body.style.overflow=l,document.removeEventListener("keydown",v,!0),t.remove(),y&&typeof y.focus=="function"&&y.focus())},g=(a="dismissed",h)=>{f||(a==="dismissed"&&e.onDismissed(h),a==="failed"&&e.onFailed(h),u())};return{el:t,dismiss:a=>g(a==="failed"||a==="no_show"?a:"dismissed")}}var ce="holdy_checklist_";function ue(i,e,t){var h,m;let n=(h=i.items)!=null?h:[];if(n.length===0)return t.onFailed({reason:"empty_items"}),{el:document.createElement("div"),dismiss:()=>{}};let o=Se(e,n),r=document.createElement("div");r.className="holdy-card holdy-checklist",r.setAttribute("role","region"),r.setAttribute("aria-label",(m=i.title)!=null?m:"Lista de tarefas");let s=document.createElement("div");if(s.className="holdy-checklist-header",i.title){let c=document.createElement("h3");c.className="holdy-checklist-title",c.textContent=i.title,s.appendChild(c)}let d=k(()=>a("dismissed"));if(s.appendChild(d),r.appendChild(s),i.text){let c=document.createElement("p");c.className="holdy-card-text",c.textContent=i.text,r.appendChild(c)}let l=document.createElement("ul");l.className="holdy-checklist-list";let y=!1,p=!1,v=()=>{l.textContent="",n.forEach(c=>{let w=document.createElement("li");w.className=o[c.id]?"holdy-checklist-item is-done":"holdy-checklist-item";let _=document.createElement("input");_.type="checkbox",_.className="holdy-checklist-checkbox",_.checked=!!o[c.id],_.setAttribute("aria-label",`Marcar ${c.label}`),_.addEventListener("change",()=>f(c,_.checked));let x=c.href?document.createElement("a"):document.createElement("span");x.className="holdy-checklist-label",x.textContent=c.label,c.href&&(x.href=c.href,x.rel="noopener noreferrer",x.addEventListener("click",()=>f(c,!0))),w.appendChild(_),w.appendChild(x),l.appendChild(w)})},f=(c,w)=>{o[c.id]=w,Ae(e,o),w&&!y&&(y=!0,t.onExecuted({item_id:c.id})),n.every(x=>o[x.id])&&!p&&(p=!0,t.onExecuted({completed:!0})),v()};v(),r.appendChild(l);let u=!1,g=()=>{u||(u=!0,r.remove())},a=(c="dismissed")=>{u||(c==="dismissed"&&t.onDismissed(),c==="failed"&&t.onFailed(),g())};return{el:r,dismiss:c=>a(c==="failed"||c==="no_show"?c:"dismissed")}}function Se(i,e){let t={};if(e.forEach(n=>{t[n.id]=!!n.completed}),typeof localStorage=="undefined")return t;try{let n=localStorage.getItem(ce+i);if(!n)return t;let o=JSON.parse(n);return e.forEach(r=>{typeof o[r.id]=="boolean"&&(t[r.id]=o[r.id])}),t}catch(n){return t}}function Ae(i,e){if(typeof localStorage!="undefined")try{localStorage.setItem(ce+i,JSON.stringify(e))}catch(t){}}var F=6,he=12;function pe(i,e,t){if(!e)return t.onFailed({reason:"anchor_unresolved"}),{el:document.createElement("div"),dismiss:()=>{}};let n=document.createElement("div");n.className="holdy-spotlight-container";let o=document.createElement("div");o.className="holdy-spotlight-backdrop",n.appendChild(o);let r=document.createElement("div");r.className="holdy-spotlight-ring",n.appendChild(r);let s=document.createElement("div");if(s.className="holdy-card holdy-spotlight-tooltip",s.setAttribute("role","dialog"),i.title){let m=document.createElement("h3");m.className="holdy-card-title",m.textContent=i.title,s.appendChild(m)}let d=C(i.text);s.appendChild(d);let l=k(()=>h("dismissed")),y=E(i,()=>{t.onExecuted(),a()}),p=T(y,l);p?s.appendChild(p):s.appendChild(l),n.appendChild(s);let v=()=>{t.onExecuted({via:"anchor_click"}),a()};e.addEventListener("click",v,{once:!0,capture:!0}),o.addEventListener("click",()=>h("dismissed",{reason:"backdrop_click"}));let f=m=>{m.key==="Escape"&&(m.stopPropagation(),h("dismissed",{reason:"esc"}))};document.addEventListener("keydown",f,!0);let u=()=>{let m=e.getBoundingClientRect();if(m.width===0&&m.height===0){h("no_show",{reason:"anchor_disappeared"});return}let c=Math.max(0,m.top-F),w=Math.max(0,m.left-F),_=m.width+F*2,x=m.height+F*2;r.style.top=`${c}px`,r.style.left=`${w}px`,r.style.width=`${_}px`,r.style.height=`${x}px`,o.style.clipPath=`polygon(
248
+ 0 0, 100% 0, 100% 100%, 0 100%, 0 0,
249
+ ${w}px ${c}px,
250
+ ${w}px ${c+x}px,
251
+ ${w+_}px ${c+x}px,
252
+ ${w+_}px ${c}px,
253
+ ${w}px ${c}px
254
+ )`;let L=s.getBoundingClientRect(),U=c+x+he,P=w+_/2-L.width/2;P<8&&(P=8);let J=window.innerWidth-L.width-8;P>J&&(P=J),U+L.height>window.innerHeight-8&&(U=c-L.height-he),s.style.top=`${Math.max(8,U)}px`,s.style.left=`${P}px`};s.style.top="-9999px",s.style.left="-9999px",requestAnimationFrame(()=>{u(),window.addEventListener("scroll",u,!0),window.addEventListener("resize",u)});let g=!1,a=()=>{g||(g=!0,n.remove(),document.removeEventListener("keydown",f,!0),window.removeEventListener("scroll",u,!0),window.removeEventListener("resize",u),e.removeEventListener("click",v,!0))},h=(m="dismissed",c)=>{g||(m==="dismissed"&&t.onDismissed(c),m==="failed"&&t.onFailed(c),a())};return{el:n,dismiss:m=>h(m==="failed"||m==="no_show"?m:"dismissed")}}var Pe=20,fe="__holdy_runtime_config_v1",Le=3600*1e3,De=1500,X=class{constructor(){this.config=null;this.transport=null;this.outcomeTracker=null;this.store=new N;this.runtime=null;this.activeWorkflow=null;this.sentiment=null;this.ring=[];this.listeners=[];this.lastEvalAt=0;this.initialized=!1;this.autoCaptureCleanup=null}async init(e){if(this.initialized){this.log("init called twice \xB7 ignoring");return}if(!e.apiKey)throw new Error("[holdy] apiKey is required");this.config=e,this.transport=new H(e),this.outcomeTracker=new M(this.transport),this.initialized=!0;let t=this.readCachedConfig();t&&(this.runtime=t);let n=await this.transport.fetchRuntimeConfig();n&&(this.runtime=n,this.writeCachedConfig(n)),this.shouldRender()&&ie(this.themeFromRuntime()),e.autoCapture&&(this.autoCaptureCleanup=Y((o,r,s,d)=>{this.track("session.activity",{kind:d,path:o,...r?{title:r}:{},...s?{referrer:s}:{}},{skipEval:d!=="route_change"})}))}identify(e){this.config&&(e.accountId!==void 0&&(this.config.accountId=e.accountId),e.userId!==void 0&&(this.config.userId=e.userId),e.sessionId!==void 0&&(this.config.sessionId=e.sessionId),(e.account||e.user)&&this.upsertIdentityRich(e.account,e.user))}async upsertIdentityRich(e,t){if(!this.transport||!e)return;let n=await this.transport.upsertAccount({account:e,user:t});!n||!this.config||(this.config.accountId||(this.config.accountId=n.account_id),!this.config.userId&&n.account_user_id&&(this.config.userId=n.account_user_id))}setWorkflow(e){this.activeWorkflow=e!=null?e:null}setSentiment(e){this.sentiment=e}async track(e,t={},n={}){if(!this.config||!this.transport){this.log("track called before init");return}let o=new Date().toISOString(),r={primitive:e,payload:t,occurred_at:o};this.pushRing(r),e==="workflow.started"&&typeof t.workflow=="string"&&(this.activeWorkflow=t.workflow),(e==="workflow.completed"||e==="workflow.abandoned")&&typeof t.workflow=="string"&&this.activeWorkflow===t.workflow&&(this.activeWorkflow=null),n.workflow!==void 0&&(this.activeWorkflow=n.workflow),this.transport.ingestBatch([{primitive:e,occurred_at:o,account_id:this.config.accountId,user_id:this.config.userId,session_id:this.config.sessionId,payload:t}]),!n.skipEval&&this.shouldTriggerEval(e)&&await this.evaluateInternal()}async evaluate(){return this.evaluateInternal(!0)}onDecision(e){return this.listeners.push(e),()=>{this.listeners=this.listeners.filter(t=>t!==e)}}reportOutcome(e,t,n){var o;(o=this.outcomeTracker)==null||o.dispatch(e,t,n)}destroy(){var e;if((e=this.transport)==null||e.destroy(),this.autoCaptureCleanup){try{this.autoCaptureCleanup()}catch(t){}this.autoCaptureCleanup=null}this.config=null,this.transport=null,this.outcomeTracker=null,this.runtime=null,this.activeWorkflow=null,this.listeners=[],this.ring.length=0,this.initialized=!1}async evaluateInternal(e=!1){var r,s;if(!this.transport||!((r=this.config)!=null&&r.accountId))return this.log("evaluate skipped \xB7 no accountId set \xB7 call identify first"),null;let t=Date.now();if(!e&&t-this.lastEvalAt<De)return null;this.lastEvalAt=t;let n={account_id:this.config.accountId,recent_primitives:[...this.ring],consumer:(s=this.config.consumer)!=null?s:"ui"};this.activeWorkflow&&(n.current_workflow=this.activeWorkflow),this.sentiment&&(n.recent_sentiment=this.sentiment);let o=await this.transport.evaluate(n);return o?(this.listeners.forEach(d=>{try{d(o)}catch(l){this.log("listener error",l)}}),o.decision_type==="intervention"&&this.shouldRender()&&this.renderDecision(o),o):null}async renderDecision(e){var s,d,l,y,p,v,f,u,g;let t=e.decision_payload;if(!t||typeof t.kind!="string"||typeof t.text!="string"){(s=this.outcomeTracker)==null||s.dispatch(e.decision_id,"failed",{reason:"invalid_payload"});return}let n={onExecuted:a=>{var h;return(h=this.outcomeTracker)==null?void 0:h.dispatch(e.decision_id,"executed",a)},onDismissed:a=>{var h;return(h=this.outcomeTracker)==null?void 0:h.dispatch(e.decision_id,"dismissed",a)},onFailed:a=>{var h;return(h=this.outcomeTracker)==null?void 0:h.dispatch(e.decision_id,"failed",a)}},o=null;try{switch(t.kind){case"tooltip":{let a=await q(t.anchor_selector);if(!a){(l=this.outcomeTracker)==null||l.dispatch(e.decision_id,"no_show",{reason:"anchor_unresolved",selector:(d=t.anchor_selector)!=null?d:null});return}o=se(t,a,n);break}case"banner":o=de(t,n);break;case"cta":o=ae(t,n);break;case"modal":o=le(t,n);break;case"checklist":o=ue(t,e.decision_id,n);break;case"spotlight":{let a=await q(t.anchor_selector);if(!a){(p=this.outcomeTracker)==null||p.dispatch(e.decision_id,"no_show",{reason:"anchor_unresolved",selector:(y=t.anchor_selector)!=null?y:null});return}o=pe(t,a,n);break}default:(v=this.outcomeTracker)==null||v.dispatch(e.decision_id,"no_show",{reason:"kind_not_supported",kind:t.kind});return}}catch(a){this.log("render error",a),n.onFailed({error:String(a)});return}if(!o)return;let r=this.store.claim(t.kind,e.decision_id,e.confidence,t.anchor_selector,()=>o.dismiss("dismissed"));r&&r.decisionId!==e.decision_id&&(r.dismiss(),(f=this.outcomeTracker)==null||f.dispatch(r.decisionId,"dismissed",{reason:"superseded",by:e.decision_id})),(g=this.outcomeTracker)==null||g.registerPending(e.decision_id,(u=this.activeWorkflow)!=null?u:void 0),oe(o.el)}shouldRender(){var e,t;return((e=this.config)==null?void 0:e.renderInterventions)===!1||(t=this.runtime)!=null&&t.features&&this.runtime.features.interventions_enabled===!1?!1:typeof document!="undefined"}shouldTriggerEval(e){return e==="workflow.started"||e==="workflow.blocked"||e==="workflow.completed"||e==="workflow.abandoned"||e==="friction.detected"||e==="support.sentiment_negative"||e==="expansion.intent_detected"||e==="expansion.ceiling_hit"}pushRing(e){for(this.ring.push(e);this.ring.length>Pe;)this.ring.shift()}themeFromRuntime(){var e;return(e=this.runtime)==null?void 0:e.theme}readCachedConfig(){if(typeof localStorage=="undefined")return null;try{let e=localStorage.getItem(fe);if(!e)return null;let t=JSON.parse(e);return Date.now()-t.at>Le?null:t.data}catch(e){return null}}writeCachedConfig(e){if(typeof localStorage!="undefined")try{localStorage.setItem(fe,JSON.stringify({at:Date.now(),data:e}))}catch(t){}}log(...e){var t;(t=this.config)!=null&&t.debug&&typeof console!="undefined"&&console.warn("[holdy]",...e)}},me=new X,Oe=me;
255
+ //# sourceMappingURL=holdy.cjs.js.map