@prodantix/sdk 0.0.1 → 0.1.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.
- package/README.md +11 -4
- package/dist/chat.cjs +65 -0
- package/dist/chat.d.cts +75 -0
- package/dist/chat.d.ts +75 -0
- package/dist/chat.js +65 -0
- package/dist/chunk-5XGN7UAV.js +2 -0
- package/dist/chunk-7J6AQICL.js +2 -0
- package/dist/chunk-VG77TYVX.js +2 -0
- package/dist/{client-B1bcIuD8.d.cts → client-BBUAoQg2.d.cts} +28 -1
- package/dist/{client-B1bcIuD8.d.ts → client-BBUAoQg2.d.ts} +28 -1
- package/dist/config-B-cTz9n1.d.ts +94 -0
- package/dist/config-OP9Csae6.d.cts +94 -0
- package/dist/csp.cjs +3 -0
- package/dist/csp.d.cts +37 -0
- package/dist/csp.d.ts +37 -0
- package/dist/csp.js +3 -0
- package/dist/http-BCh716Vs.d.cts +14 -0
- package/dist/http-BCh716Vs.d.ts +14 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +15 -5
- package/dist/index.d.ts +15 -5
- package/dist/index.js +1 -1
- package/dist/messenger.cjs +2 -0
- package/dist/messenger.d.cts +2 -0
- package/dist/messenger.d.ts +2 -0
- package/dist/messenger.iife.js +65 -0
- package/dist/messenger.js +2 -0
- package/dist/node.cjs +1 -1
- package/dist/node.d.cts +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/node.js +1 -1
- package/dist/{transport-By6wsdny.d.ts → transport-DhhzvwpV.d.cts} +3 -15
- package/dist/{transport-B3PxeUxW.d.cts → transport-dWp3NUMj.d.ts} +3 -15
- package/dist/web.cjs +1 -1
- package/dist/web.d.cts +3 -2
- package/dist/web.d.ts +3 -2
- package/dist/web.js +1 -1
- package/package.json +19 -3
- package/dist/chunk-FIZWZVZG.js +0 -2
package/README.md
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
# Prodantix SDK
|
|
2
2
|
|
|
3
|
-
Isomorphic, zero-dependency analytics + feature-flag client for Prodantix.
|
|
4
|
-
browser, Node, and edge runtimes. Ships dual ESM/CJS with full TypeScript types.
|
|
3
|
+
Isomorphic, zero-dependency analytics + feature-flag client for [Prodantix](https://prodantix.com).
|
|
4
|
+
Runs in the browser, Node, and edge runtimes. Ships dual ESM/CJS with full TypeScript types.
|
|
5
|
+
|
|
6
|
+
## Docs
|
|
7
|
+
|
|
8
|
+
- [Quickstart](https://prodantix.com/en/docs/quickstart): install and send a first event
|
|
9
|
+
- [Get an API key](https://prodantix.com/en/docs/keys): signup, project creation, where the key lives
|
|
10
|
+
- [API reference](https://prodantix.com/en/docs/api): every REST operation, rendered
|
|
11
|
+
- React apps: pair with [`@prodantix/react`](https://www.npmjs.com/package/@prodantix/react), the provider + hook adapter
|
|
5
12
|
|
|
6
13
|
## Install
|
|
7
14
|
|
|
@@ -74,8 +81,8 @@ anywhere.
|
|
|
74
81
|
|
|
75
82
|
| Option | Default | Notes |
|
|
76
83
|
| --- | --- | --- |
|
|
77
|
-
| `apiKey` |
|
|
78
|
-
| `host` |
|
|
84
|
+
| `apiKey` | required | Public project key (`pdx_pub_…`). Required. |
|
|
85
|
+
| `host` | required | Ingest base URL. Required. |
|
|
79
86
|
| `flagsHost` | `host` | Flag-eval base URL (`GET /v1/flags`). |
|
|
80
87
|
| `flushAt` | `20` | Flush when this many events are queued. |
|
|
81
88
|
| `flushIntervalMs` | `10000` | Periodic flush interval; `0` disables the timer. |
|
package/dist/chat.cjs
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
'use strict';var I=Object.defineProperty;var O=(n,e,t)=>e in n?I(n,e,{enumerable:true,configurable:true,writable:true,value:t}):n[e]=t;var l=(n,e,t)=>O(n,typeof e!="symbol"?e+"":e,t);function w(n){if(n)return n;let e=globalThis.fetch;if(typeof e=="function")return e.bind(globalThis)}function A(n){return n.replace(/\/+$/,"")}var H="X-Prodantix-Conversation-Token",E="prodantix.chat.handle";function M(){let n=globalThis.localStorage;if(n)return {get:e=>n.getItem(e),remove:e=>n.removeItem(e),set:(e,t)=>n.setItem(e,t)}}var f=class{constructor(e){this.options=e;l(this,"fetchImpl");l(this,"host");l(this,"storage");l(this,"handle");l(this,"identity",null);this.fetchImpl=w(e.fetchImpl),this.host=A(e.host),this.storage=e.storage??M(),this.handle=this.readHandle();}get hasThread(){return this.handle!==null}get socketAuth(){return this.handle?{conversationId:this.handle.conversationId,conversationToken:this.handle.token,projectKey:this.options.apiKey}:null}identify(e){this.identity=e;}async ensureThread(e){if(this.handle)return true;let t=await this.request("POST","/v1/conversations",{body:{distinctId:this.options.distinctId,subject:e,userHash:this.identity?.userHash,userId:this.identity?.userId}});return !t?.conversationId||!t.token?false:(this.handle={conversationId:t.conversationId,token:t.token},this.storage?.set(E,JSON.stringify(this.handle)),true)}async send(e){if(!await this.ensureThread())return null;let t=this.handle;return t?(await this.request("POST",`/v1/conversations/${encodeURIComponent(t.conversationId)}/turns`,{body:{body:e},token:t.token}))?.turn??null:null}async load(){let e=this.handle;return e?this.request("GET",`/v1/conversations/${encodeURIComponent(e.conversationId)}`,{token:e.token}):null}readHandle(){let e=this.storage?.get(E);if(!e)return null;try{let t=JSON.parse(e);if(typeof t.conversationId=="string"&&typeof t.token=="string")return {conversationId:t.conversationId,token:t.token}}catch{}return this.storage?.remove(E),null}async request(e,t,r={}){let i=this.fetchImpl;if(!i)return this.options.onError?.(new Error("no fetch available for prodantix chat")),null;let a={authorization:`Bearer ${this.options.apiKey}`,"content-type":"application/json"};r.token&&(a[H]=r.token);try{let s=await i(`${this.host}${t}`,{body:r.body===void 0?void 0:JSON.stringify(r.body),headers:a,method:e}),o=await s.text();return s.ok?o?JSON.parse(o):{}:(this.options.onError?.(new Error(`prodantix chat ${t}: ${s.status}`)),null)}catch(s){return this.options.onError?.(s),null}}};var h={bubbleStyle:"tailed",launcherStyle:"circle_outlined",namePlacement:"avatar_only",skin:"concierge",timestampStyle:"cluster"},F=["concierge","console","quiet"],R=["avatar_circle","circle_filled","circle_outlined","pill_labelled","pill_team","squircle_filled"],$=["hairline","outlined","rounded","tailed"],K=["above","avatar_only","gutter","hidden","inline"],z=["cluster","latency","none","trailing","with_name"],b=(n,e,t)=>typeof n=="string"&&e.includes(n)?n:t;function y(n){let e={bubbleStyle:b(n?.bubbleStyle,$,h.bubbleStyle),launcherStyle:b(n?.launcherStyle,R,h.launcherStyle),namePlacement:b(n?.namePlacement,K,h.namePlacement),skin:b(n?.skin,F,h.skin),timestampStyle:b(n?.timestampStyle,z,h.timestampStyle)};return (e.namePlacement==="avatar_only"||e.namePlacement==="hidden")&&(e.timestampStyle==="with_name"||e.timestampStyle==="latency")&&(e.timestampStyle="trailing"),e.namePlacement==="inline"&&e.bubbleStyle==="hairline"&&(e.namePlacement="above"),e}var G={agentLabel:"Agent",aiLabel:"AI",closeLabel:"Close chat",emptyBody:"We usually reply within a few minutes.",emptyTitle:"Ask us anything.",inputPlaceholder:"Type a message",launcherLabel:"Open support chat",sendLabel:"Send",timeLabel:n=>{let e=new Date(n);return Number.isNaN(e.getTime())?"":`${String(e.getHours()).padStart(2,"0")}:${String(e.getMinutes()).padStart(2,"0")}`},title:"Support",unreadLabel:n=>`${n} unread`},v={accentColor:"#5b5bff",greeting:"",launcherOffsetX:20,launcherOffsetY:20,launcherPosition:"bottom_right",starterPrompts:[],...h},B={concierge:".panel{border-radius:16px;box-shadow:0 16px 40px rgba(0,0,0,.2)}.header{background:var(--a);color:#fff;flex-direction:column;align-items:flex-start;gap:14px;padding:18px 14px 20px 20px}.header h2{font-size:19px;font-weight:640}.composer{padding:12px 12px 14px;gap:8px}.composer input{border:0;background:var(--fill);height:46px;border-radius:23px;padding:0 16px}.composer button{width:46px;min-width:46px;height:46px;padding:0;border-radius:23px}.composer button .sendglyph{display:block}.composer button .sendtext{display:none}",console:".panel{border-radius:12px;box-shadow:0 8px 24px rgba(0,0,0,.16)}.header{background:var(--paper);color:var(--ink);border-bottom:1px solid var(--hairline)}.close{color:var(--ink-2)}",quiet:".composer{position:relative;padding:10px 12px 12px}.composer input{height:42px;padding-right:42px}.composer button{position:absolute;top:50%;right:16px;width:34px;min-width:34px;height:34px;padding:0;background:transparent;color:var(--ink);border-radius:7px;transform:translateY(-50%)}.composer button .sendglyph{display:block;width:18px;height:18px}.composer button .sendtext{display:none}.panel{border-radius:8px;box-shadow:0 2px 8px rgba(0,0,0,.12)}.header{background:var(--paper);color:var(--ink);height:44px;padding:0 8px 0 16px;border-bottom:1px solid var(--hairline)}.header h2{font-size:11px;letter-spacing:.11em;text-transform:uppercase;color:var(--ink-3)}.close{color:var(--ink-2)}"},D={avatar_circle:".launcher{width:60px;height:60px;border-radius:30px;background:var(--paper);border:1px solid var(--hairline);color:var(--ink-2)}",circle_filled:".launcher{width:56px;height:56px;border-radius:28px;background:var(--a);color:#fff}",circle_outlined:".launcher{width:46px;height:46px;border-radius:23px;background:var(--paper);border:1px solid var(--hairline);color:var(--ink-2);box-shadow:0 1px 2px rgba(0,0,0,.08);font-size:21px}.badge{background:var(--a);top:-7px;right:-7px;min-width:19px;height:19px;border-radius:10px;font-size:11.5px}",pill_labelled:".launcher{width:auto;height:52px;border-radius:26px;padding:0 22px;gap:10px;background:var(--a);color:#fff;font-size:14.5px;font-weight:600}",pill_team:".launcher{width:auto;height:54px;border-radius:27px;padding:0 20px 0 8px;gap:10px;background:var(--paper);border:1px solid var(--hairline);color:var(--ink);font-size:14px;font-weight:600}.badge{position:static;background:var(--a)}",squircle_filled:".launcher{width:56px;height:56px;border-radius:16px;background:var(--a);color:#fff}"},q={hairline:".turn{max-width:100%;padding:13px 0;border-top:1px solid var(--hairline);background:none;border-radius:0}.log>.turn:first-child{border-top:0}.turn.end_user{align-self:stretch;display:flex;flex-direction:column;align-items:flex-end}.turn.end_user .body{background:var(--fill);color:var(--ink);border-radius:8px;padding:9px 12px;max-width:85%}",outlined:".turn{background:none;border:1px solid var(--hairline);border-radius:12px}.turn.end_user{background:none;border-color:var(--a);color:var(--ink)}",rounded:".turn{border-radius:18px;padding:10px 15px}",tailed:".turn.agent,.turn.ai{border-radius:12px 12px 12px 4px}.turn.end_user{border-radius:12px 12px 4px 12px}"},U={above:"",avatar_only:".turn.agent,.turn.ai{display:flex;gap:10px;max-width:100%;background:none;padding:0}.turn .body{background:var(--fill);padding:9px 13px;border-radius:inherit}",gutter:".turn.agent,.turn.ai{display:flex;gap:10px;max-width:100%;background:none;padding:0}.turn .body{background:var(--fill);padding:9px 13px;border-radius:inherit}.author{text-transform:none;letter-spacing:0;font-size:12.5px;font-weight:600;opacity:1}",hidden:".turn.agent .author,.turn.ai .author:not(.ai){display:none}",inline:".author{display:inline;margin-right:6px;font-weight:650}"},j={cluster:'.divider{display:flex;align-items:center;gap:10px;margin:0;font-size:11px;opacity:.6}.divider:before,.divider:after{content:"";flex:1;height:1px;background:var(--hairline)}',latency:".stamp{font-size:11px;opacity:.7;margin-left:6px}.lat{font-size:11px;opacity:.7;margin-left:6px}",none:"",trailing:".stamp{display:block;font-size:11px;opacity:.7;margin-top:4px}.turn.end_user .stamp{text-align:right}",with_name:".stamp{font-size:11px;opacity:.7;margin-left:6px}"};function N(n){let e=y(n),t=n.launcherPosition==="bottom_left"?"left":"right",r=n.accentColor;return `${`
|
|
2
|
+
:host {
|
|
3
|
+
all: initial; --a: ${r};
|
|
4
|
+
--paper: #fff; --ink: #0f172a; --ink-3: var(--ink-3);
|
|
5
|
+
--fill: #f1f5f9; --hairline: #e2e8f0; --field: #cbd5e1; --ink-2: rgba(0,0,0,.72);
|
|
6
|
+
color-scheme: light dark;
|
|
7
|
+
}
|
|
8
|
+
@media (prefers-color-scheme: dark) {
|
|
9
|
+
:host {
|
|
10
|
+
--paper: oklch(24.6% 0.015 257); --ink: #fff; --ink-3: rgba(255,255,255,.55);
|
|
11
|
+
--fill: rgba(255,255,255,.06); --hairline: rgba(255,255,255,.13); --field: rgba(255,255,255,.22); --ink-2: rgba(255,255,255,.70);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
* { box-sizing: border-box; font-family: system-ui, sans-serif; }
|
|
15
|
+
.launcher {
|
|
16
|
+
position: fixed; ${t}: ${n.launcherOffsetX}px; bottom: ${n.launcherOffsetY}px; width: 56px; height: 56px;
|
|
17
|
+
border-radius: 28px; border: none; cursor: pointer;
|
|
18
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
19
|
+
background: ${r}; color: #fff; font-size: 24px;
|
|
20
|
+
box-shadow: 0 4px 12px rgba(0,0,0,.2);
|
|
21
|
+
}
|
|
22
|
+
.launcher:focus-visible { outline: 3px solid #0b0e14; outline-offset: 2px; }
|
|
23
|
+
.badge {
|
|
24
|
+
position: absolute; top: -4px; right: -4px; min-width: 20px; height: 20px;
|
|
25
|
+
border-radius: 10px; background: #dc2626; color: #fff; font-size: 12px;
|
|
26
|
+
display: flex; align-items: center; justify-content: center; padding: 0 4px;
|
|
27
|
+
}
|
|
28
|
+
.panel {
|
|
29
|
+
position: fixed; ${t}: ${n.launcherOffsetX}px; bottom: ${n.launcherOffsetY+68}px; width: 360px; max-width: calc(100vw - 40px);
|
|
30
|
+
height: 520px; max-height: calc(100vh - 120px); background: var(--paper); color: var(--ink);
|
|
31
|
+
border-radius: 12px; box-shadow: 0 8px 32px rgba(0,0,0,.24);
|
|
32
|
+
display: flex; flex-direction: column; overflow: hidden;
|
|
33
|
+
}
|
|
34
|
+
.header { padding: 14px 16px; background: #0b0e14; color: #fff; display: flex; align-items: center; justify-content: space-between; }
|
|
35
|
+
.header h2 { margin: 0; font-size: 15px; }
|
|
36
|
+
.close { background: none; border: none; color: #fff; cursor: pointer; font-size: 18px; }
|
|
37
|
+
.close:focus-visible { outline: 2px solid #fff; }
|
|
38
|
+
.log { flex: 1; overflow-y: auto; padding: 12px; display: flex; flex-direction: column; gap: 8px; }
|
|
39
|
+
.turn { max-width: 80%; padding: 8px 12px; border-radius: 12px; font-size: 14px; }
|
|
40
|
+
.turn.end_user { align-self: flex-end; background: ${r}; color: #fff; }
|
|
41
|
+
.turn.agent, .turn.ai { align-self: flex-start; background: var(--fill); color: var(--ink); }
|
|
42
|
+
.author { font-size: 11px; opacity: .7; margin-bottom: 2px; }
|
|
43
|
+
.empty { display: flex; flex-direction: column; gap: 8px; padding: 20px 16px; }
|
|
44
|
+
.empty h3 { margin: 0; font-size: 18px; font-weight: 640; letter-spacing: -.015em; }
|
|
45
|
+
.empty p { margin: 0 0 8px; font-size: 13.5px; color: var(--ink-2); }
|
|
46
|
+
.prompt {
|
|
47
|
+
display: flex; align-items: center; min-height: 44px; padding: 0 14px; text-align: left;
|
|
48
|
+
font-family: inherit; font-size: 13.5px; font-weight: 500; color: var(--ink);
|
|
49
|
+
background: none; border: 1px solid var(--hairline); border-radius: 8px; cursor: pointer;
|
|
50
|
+
}
|
|
51
|
+
.prompt:focus-visible { outline: 2px solid ${r}; outline-offset: 2px; }
|
|
52
|
+
.av { width: 30px; height: 30px; border-radius: 50%; flex: none; display: inline-flex; align-items: center; justify-content: center; font-size: 11.5px; font-weight: 650; color: #fff; background: #7c3f3f; }
|
|
53
|
+
.av.bot { border-radius: 9px; background: var(--fill); color: var(--ink); }
|
|
54
|
+
.composer { display: flex; gap: 8px; padding: 12px; border-top: 1px solid var(--hairline); }
|
|
55
|
+
.composer input { flex: 1; padding: 8px 10px; border: 1px solid var(--field); border-radius: 8px; font-size: 14px; background: transparent; color: var(--ink); }
|
|
56
|
+
.composer input:focus-visible { outline: 2px solid ${r}; }
|
|
57
|
+
.composer button { display: inline-flex; align-items: center; justify-content: center; gap: 0; min-width: 64px; height: 44px; padding: 0 16px; background: ${r}; color: #fff; border: none; border-radius: 8px; cursor: pointer; font-family: inherit; font-size: 14.5px; font-weight: 550; }
|
|
58
|
+
.composer button .sendglyph { display: none; width: 19px; height: 19px; }
|
|
59
|
+
.composer button:focus-visible { outline: 2px solid #0b0e14; }
|
|
60
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
61
|
+
.panel { animation: rise 180ms ease-out; }
|
|
62
|
+
@keyframes rise { from { transform: translateY(8px); opacity: 0; } to { transform: none; opacity: 1; } }
|
|
63
|
+
}
|
|
64
|
+
`}${B[e.skin]}${D[e.launcherStyle]}${q[e.bubbleStyle]}${U[e.namePlacement]}${j[e.timestampStyle]}`}var W=["end_user","agent","ai"],x=class{constructor(e,t,r={},i={}){this.host=e;this.client=t;l(this,"root");l(this,"strings");l(this,"settings");l(this,"appearance");l(this,"launcher");l(this,"badge");l(this,"panel",null);l(this,"lastFocused",null);l(this,"unread",0);this.strings={...G,...r},this.appearance={...v,...i},this.settings=y({...v,...i}),this.root=e.attachShadow({mode:"closed"});let a=document.createElement("style");a.textContent=N({...v,...i}),this.root.append(a),this.launcher=document.createElement("button"),this.launcher.className="launcher",this.launcher.type="button",this.launcher.setAttribute("aria-haspopup","dialog"),this.launcher.setAttribute("aria-label",this.strings.launcherLabel),this.launcher.textContent="\u{1F4AC}",this.launcher.addEventListener("click",()=>this.toggle()),this.badge=document.createElement("span"),this.badge.className="badge",this.badge.hidden=true,this.launcher.append(this.badge),this.root.append(this.launcher);}toggle(){this.panel?this.close():this.open();}async open(){if(this.panel)return;this.lastFocused=this.host.ownerDocument.activeElement,this.unread=0,this.renderBadge();let e=document.createElement("section");e.className="panel",e.setAttribute("role","dialog"),e.setAttribute("aria-modal","true"),e.setAttribute("aria-label",this.strings.title);let t=document.createElement("div");t.className="header";let r=document.createElement("h2");r.textContent=this.strings.title;let i=document.createElement("button");i.className="close",i.type="button",i.setAttribute("aria-label",this.strings.closeLabel),i.textContent="\xD7",i.addEventListener("click",()=>this.close()),t.append(r,i);let a=document.createElement("div");a.className="log",a.setAttribute("role","log"),a.setAttribute("aria-live","polite"),a.setAttribute("aria-label",this.strings.title);let s=document.createElement("form");s.className="composer";let o=document.createElement("input");o.type="text",o.setAttribute("aria-label",this.strings.inputPlaceholder),o.placeholder=this.strings.inputPlaceholder;let p=document.createElement("button");p.type="submit",p.setAttribute("aria-label",this.strings.sendLabel),p.innerHTML='<svg class="sendglyph" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4.5 12 20 4.5 15 20l-3.6-5.4L4.5 12Z"/></svg>';let u=document.createElement("span");u.className="sendtext",u.textContent=this.strings.sendLabel,p.append(u),s.append(o,p),s.addEventListener("submit",g=>{g.preventDefault(),this.submit(o,a);}),e.append(t,a,s),e.addEventListener("keydown",g=>this.onKeydown(g,e,i)),this.root.append(e),this.panel=e,o.focus();let d=await this.client.load();d&&d.turns.length>0?this.renderThread(a,d):this.renderFirstRun(a,o);}renderFirstRun(e,t){let r=document.createElement("div");r.className="empty";let i=document.createElement("h3");i.textContent=this.appearance.greeting.trim()||this.strings.emptyTitle;let a=document.createElement("p");a.textContent=this.strings.emptyBody,r.append(i,a);for(let s of this.appearance.starterPrompts){let o=document.createElement("button");o.className="prompt",o.type="button",o.textContent=s,o.addEventListener("click",()=>{t.value=s,this.submit(t,e);}),r.append(o);}e.replaceChildren(r);}close(){this.panel&&(this.panel.remove(),this.panel=null,this.lastFocused instanceof HTMLElement?this.lastFocused.focus():this.launcher.focus());}onIncomingTurn(e){if(this.panel){let t=this.panel.querySelector(".log");t instanceof HTMLElement&&this.appendTurn(t,e);return}e.authorKind!=="end_user"&&(this.unread+=1,this.renderBadge());}async submit(e,t){let r=e.value.trim();if(!r)return;e.value="",t.querySelector(".empty")?.remove();let i=await this.client.send(r);i&&this.appendTurn(t,i);}renderThread(e,t){e.replaceChildren();for(let r of t.turns)this.appendTurn(e,r);}appendTurn(e,t){e.querySelector(".empty")?.remove();let r=W.includes(t.authorKind)?t.authorKind:"agent",i=this.settings,a=document.createElement("div");if(a.className=`turn ${r}`,r!=="end_user"&&(i.namePlacement==="avatar_only"||i.namePlacement==="gutter")){let d=document.createElement("span");d.className=r==="ai"?"av bot":"av",d.textContent=r==="ai"?this.strings.aiLabel:this.strings.agentLabel.slice(0,2).toUpperCase(),d.setAttribute("aria-hidden","true"),a.append(d);}let o=document.createElement("div");if(o.className="body",r!=="end_user"&&i.namePlacement!=="hidden"&&!(i.namePlacement==="avatar_only"&&r==="agent")||r==="ai"&&i.namePlacement==="hidden"){let d=document.createElement("div");d.className=r==="ai"?"author ai":"author",d.textContent=r==="ai"?this.strings.aiLabel:this.strings.agentLabel,(i.timestampStyle==="with_name"||i.timestampStyle==="latency")&&d.append(this.stamp(t)),o.append(d);}let u=document.createElement("div");u.textContent=t.body,o.append(u),i.timestampStyle==="trailing"&&o.append(this.stamp(t)),a.append(o),e.append(a),e.scrollTop=e.scrollHeight;}stamp(e){let t=document.createElement("span");return t.className="stamp",t.textContent=this.strings.timeLabel(e.createdAt),t}onKeydown(e,t,r){if(e.key==="Escape"){e.preventDefault(),this.close();return}if(e.key!=="Tab")return;let i=t.querySelectorAll('button, input, [tabindex]:not([tabindex="-1"])');if(i.length===0)return;let a=i[0],s=i[i.length-1],o=this.root.activeElement;e.shiftKey&&o===a?(e.preventDefault(),s.focus()):!e.shiftKey&&o===s?(e.preventDefault(),a.focus()):o===null&&(e.preventDefault(),r.focus());}renderBadge(){this.unread>0?(this.badge.hidden=false,this.badge.textContent=String(this.unread),this.launcher.setAttribute("aria-label",`${this.strings.launcherLabel}, ${this.strings.unreadLabel(this.unread)}`)):(this.badge.hidden=true,this.badge.textContent="",this.launcher.setAttribute("aria-label",this.strings.launcherLabel));}};function _(n){return `40${JSON.stringify(n)}`}function P(){return "3"}function L(n){let e=n.charAt(0),t=n.slice(1);if(e==="2")return {kind:"ping"};if(e==="1")return {kind:"disconnect"};if(e==="0"){let s=T(t);return {kind:"open",pingInterval:typeof s?.pingInterval=="number"?s.pingInterval:25e3,pingTimeout:typeof s?.pingTimeout=="number"?s.pingTimeout:2e4}}if(e!=="4")return {kind:"other"};let r=t.charAt(0),i=t.slice(1);if(r==="0")return {kind:"connected"};if(r==="1")return {kind:"disconnect"};if(r==="4"){let s=T(i);return {kind:"connectError",message:typeof s?.message=="string"?s.message:"refused"}}if(r!=="2")return {kind:"other"};let a=T(i);return !Array.isArray(a)||typeof a[0]!="string"?{kind:"other"}:{kind:"event",name:a[0],payload:a[1]}}function T(n){try{return JSON.parse(n)}catch{return null}}var Y="/socket.io/?EIO=4&transport=websocket",k=class{constructor(e){this.options=e;l(this,"socket",null);l(this,"heartbeat",null);l(this,"ready",false);l(this,"closed",false);l(this,"heartbeatWindow",45e3);l(this,"factory");l(this,"setTimer");l(this,"clearTimer");this.factory=e.socketFactory??J,this.setTimer=e.setTimer??((t,r)=>setTimeout(t,r)),this.clearTimer=e.clearTimer??(t=>clearTimeout(t));}open(){if(this.socket||this.closed)return;let e=`${this.options.host.replace(/^http/,"ws").replace(/\/+$/,"")}${Y}`,t;try{t=this.factory(e);}catch{this.options.onClosed(false);return}this.socket=t,t.onmessage=r=>this.receive(String(r.data)),t.onerror=()=>t.close(),t.onclose=()=>this.fell();}close(){this.closed=true,this.stopHeartbeat();let e=this.socket;this.socket=null,e?.close();}receive(e){let t=L(e);if(t.kind==="open"){this.armHeartbeat(t.pingInterval+t.pingTimeout),this.socket?.send(_(this.options.auth));return}if(t.kind==="ping"){this.armHeartbeat(),this.socket?.send(P());return}if(t.kind==="connectError"||t.kind==="disconnect"){this.stopHeartbeat(),this.socket?.close();return}if(t.kind==="event"){if(t.name==="ready"){this.ready=true,this.options.onReady();return}if(t.name==="conversation.turn"){let r=t.payload?.turn;r&&this.options.onTurn(r);}}}fell(){this.stopHeartbeat();let e=this.ready;this.socket=null,this.ready=false,this.closed||this.options.onClosed(e);}armHeartbeat(e){e!==void 0&&(this.heartbeatWindow=e),this.stopHeartbeat(),this.heartbeat=this.setTimer(()=>this.socket?.close(),this.heartbeatWindow);}stopHeartbeat(){this.heartbeat!==null&&this.clearTimer(this.heartbeat),this.heartbeat=null;}};function J(n){let e=globalThis.WebSocket;if(!e)throw new Error("no WebSocket");return new e(n)}function ue(n){let e=globalThis.document;if(!e)throw new Error("prodantix chat requires a document; mount it in the browser");let t=n.mountPoint??e.createElement("div");n.mountPoint||e.body.append(t);let r=new f(n),i=new x(t,r,n.strings,n.appearance),a=new Set,s,o=null,p=n.pollIntervalMs??15e3,u=c=>{a.has(c.id)||c.authorKind==="end_user"||(a.add(c.id),i.onIncomingTurn(c));},d=async()=>{if(!r.hasThread)return;let c=await r.load();if(c){for(let m of c.turns)u(m);a=new Set(c.turns.map(m=>m.id));}},g=()=>{s||p<=0||(s=setInterval(()=>void d(),p));},C=()=>{s&&clearInterval(s),s=void 0;},S=()=>{if(o||!n.socketHost)return;let c=r.socketAuth;c&&(o=new k({auth:c,host:n.socketHost,onClosed:m=>{o=null,g(),m&&S();},onReady:C,onTurn:u,socketFactory:n.socketFactory}),o.open());};return g(),S(),{close:()=>i.close(),destroy:()=>{C(),o?.close(),o=null,i.close(),t.remove();},identify:c=>r.identify(c),open:()=>{i.open().then(S);}}}exports.ChatClient=f;exports.ChatPanel=x;exports.DEFAULT_APPEARANCE=v;exports.DEFAULT_APPEARANCE_SETTINGS=h;exports.mountChat=ue;exports.panelStyles=N;exports.resolveAppearance=y;//# sourceMappingURL=chat.cjs.map
|
|
65
|
+
//# sourceMappingURL=chat.cjs.map
|
package/dist/chat.d.cts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { C as ChatClient, M as MessengerConfig, A as AppearanceSettings, a as ChatTurn, b as ChatIdentity, c as ChatClientOptions } from './config-OP9Csae6.cjs';
|
|
2
|
+
export { B as BubbleStyle, d as ChatStorage, e as ChatThread, D as DEFAULT_APPEARANCE_SETTINGS, L as LauncherStyle, f as MessengerSkin, N as NamePlacement, T as TimestampStyle, r as resolveAppearance } from './config-OP9Csae6.cjs';
|
|
3
|
+
import './http-BCh716Vs.cjs';
|
|
4
|
+
|
|
5
|
+
interface ChatStrings {
|
|
6
|
+
launcherLabel: string;
|
|
7
|
+
title: string;
|
|
8
|
+
inputPlaceholder: string;
|
|
9
|
+
sendLabel: string;
|
|
10
|
+
closeLabel: string;
|
|
11
|
+
agentLabel: string;
|
|
12
|
+
aiLabel: string;
|
|
13
|
+
unreadLabel: (count: number) => string;
|
|
14
|
+
timeLabel: (createdAt: string) => string;
|
|
15
|
+
emptyTitle: string;
|
|
16
|
+
emptyBody: string;
|
|
17
|
+
}
|
|
18
|
+
type MessengerAppearance = Pick<MessengerConfig, 'accentColor' | 'greeting' | 'launcherOffsetX' | 'launcherOffsetY' | 'launcherPosition' | 'starterPrompts'> & AppearanceSettings;
|
|
19
|
+
declare const DEFAULT_APPEARANCE: MessengerAppearance;
|
|
20
|
+
declare function panelStyles(appearance: MessengerAppearance): string;
|
|
21
|
+
declare class ChatPanel {
|
|
22
|
+
private readonly host;
|
|
23
|
+
private readonly client;
|
|
24
|
+
private readonly root;
|
|
25
|
+
private readonly strings;
|
|
26
|
+
private readonly settings;
|
|
27
|
+
private readonly appearance;
|
|
28
|
+
private readonly launcher;
|
|
29
|
+
private readonly badge;
|
|
30
|
+
private panel;
|
|
31
|
+
private lastFocused;
|
|
32
|
+
private unread;
|
|
33
|
+
constructor(host: HTMLElement, client: ChatClient, strings?: Partial<ChatStrings>, appearance?: Partial<MessengerAppearance>);
|
|
34
|
+
private toggle;
|
|
35
|
+
open(): Promise<void>;
|
|
36
|
+
private renderFirstRun;
|
|
37
|
+
close(): void;
|
|
38
|
+
onIncomingTurn(turn: ChatTurn): void;
|
|
39
|
+
private submit;
|
|
40
|
+
private renderThread;
|
|
41
|
+
private appendTurn;
|
|
42
|
+
private stamp;
|
|
43
|
+
private onKeydown;
|
|
44
|
+
private renderBadge;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface SocketLike {
|
|
48
|
+
send(data: string): void;
|
|
49
|
+
close(): void;
|
|
50
|
+
onopen: (() => void) | null;
|
|
51
|
+
onclose: (() => void) | null;
|
|
52
|
+
onerror: (() => void) | null;
|
|
53
|
+
onmessage: ((event: {
|
|
54
|
+
data: string;
|
|
55
|
+
}) => void) | null;
|
|
56
|
+
}
|
|
57
|
+
type SocketFactory = (url: string) => SocketLike;
|
|
58
|
+
|
|
59
|
+
interface MountChatOptions extends ChatClientOptions {
|
|
60
|
+
mountPoint?: HTMLElement;
|
|
61
|
+
strings?: Partial<ChatStrings>;
|
|
62
|
+
appearance?: Partial<MessengerAppearance>;
|
|
63
|
+
pollIntervalMs?: number;
|
|
64
|
+
socketHost?: string;
|
|
65
|
+
socketFactory?: SocketFactory;
|
|
66
|
+
}
|
|
67
|
+
interface ChatHandle {
|
|
68
|
+
open(): void;
|
|
69
|
+
close(): void;
|
|
70
|
+
destroy(): void;
|
|
71
|
+
identify(identity: ChatIdentity): void;
|
|
72
|
+
}
|
|
73
|
+
declare function mountChat(options: MountChatOptions): ChatHandle;
|
|
74
|
+
|
|
75
|
+
export { AppearanceSettings, ChatClient, ChatClientOptions, type ChatHandle, ChatIdentity, ChatPanel, type ChatStrings, ChatTurn, DEFAULT_APPEARANCE, type MessengerAppearance, type MountChatOptions, mountChat, panelStyles };
|
package/dist/chat.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { C as ChatClient, M as MessengerConfig, A as AppearanceSettings, a as ChatTurn, b as ChatIdentity, c as ChatClientOptions } from './config-B-cTz9n1.js';
|
|
2
|
+
export { B as BubbleStyle, d as ChatStorage, e as ChatThread, D as DEFAULT_APPEARANCE_SETTINGS, L as LauncherStyle, f as MessengerSkin, N as NamePlacement, T as TimestampStyle, r as resolveAppearance } from './config-B-cTz9n1.js';
|
|
3
|
+
import './http-BCh716Vs.js';
|
|
4
|
+
|
|
5
|
+
interface ChatStrings {
|
|
6
|
+
launcherLabel: string;
|
|
7
|
+
title: string;
|
|
8
|
+
inputPlaceholder: string;
|
|
9
|
+
sendLabel: string;
|
|
10
|
+
closeLabel: string;
|
|
11
|
+
agentLabel: string;
|
|
12
|
+
aiLabel: string;
|
|
13
|
+
unreadLabel: (count: number) => string;
|
|
14
|
+
timeLabel: (createdAt: string) => string;
|
|
15
|
+
emptyTitle: string;
|
|
16
|
+
emptyBody: string;
|
|
17
|
+
}
|
|
18
|
+
type MessengerAppearance = Pick<MessengerConfig, 'accentColor' | 'greeting' | 'launcherOffsetX' | 'launcherOffsetY' | 'launcherPosition' | 'starterPrompts'> & AppearanceSettings;
|
|
19
|
+
declare const DEFAULT_APPEARANCE: MessengerAppearance;
|
|
20
|
+
declare function panelStyles(appearance: MessengerAppearance): string;
|
|
21
|
+
declare class ChatPanel {
|
|
22
|
+
private readonly host;
|
|
23
|
+
private readonly client;
|
|
24
|
+
private readonly root;
|
|
25
|
+
private readonly strings;
|
|
26
|
+
private readonly settings;
|
|
27
|
+
private readonly appearance;
|
|
28
|
+
private readonly launcher;
|
|
29
|
+
private readonly badge;
|
|
30
|
+
private panel;
|
|
31
|
+
private lastFocused;
|
|
32
|
+
private unread;
|
|
33
|
+
constructor(host: HTMLElement, client: ChatClient, strings?: Partial<ChatStrings>, appearance?: Partial<MessengerAppearance>);
|
|
34
|
+
private toggle;
|
|
35
|
+
open(): Promise<void>;
|
|
36
|
+
private renderFirstRun;
|
|
37
|
+
close(): void;
|
|
38
|
+
onIncomingTurn(turn: ChatTurn): void;
|
|
39
|
+
private submit;
|
|
40
|
+
private renderThread;
|
|
41
|
+
private appendTurn;
|
|
42
|
+
private stamp;
|
|
43
|
+
private onKeydown;
|
|
44
|
+
private renderBadge;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface SocketLike {
|
|
48
|
+
send(data: string): void;
|
|
49
|
+
close(): void;
|
|
50
|
+
onopen: (() => void) | null;
|
|
51
|
+
onclose: (() => void) | null;
|
|
52
|
+
onerror: (() => void) | null;
|
|
53
|
+
onmessage: ((event: {
|
|
54
|
+
data: string;
|
|
55
|
+
}) => void) | null;
|
|
56
|
+
}
|
|
57
|
+
type SocketFactory = (url: string) => SocketLike;
|
|
58
|
+
|
|
59
|
+
interface MountChatOptions extends ChatClientOptions {
|
|
60
|
+
mountPoint?: HTMLElement;
|
|
61
|
+
strings?: Partial<ChatStrings>;
|
|
62
|
+
appearance?: Partial<MessengerAppearance>;
|
|
63
|
+
pollIntervalMs?: number;
|
|
64
|
+
socketHost?: string;
|
|
65
|
+
socketFactory?: SocketFactory;
|
|
66
|
+
}
|
|
67
|
+
interface ChatHandle {
|
|
68
|
+
open(): void;
|
|
69
|
+
close(): void;
|
|
70
|
+
destroy(): void;
|
|
71
|
+
identify(identity: ChatIdentity): void;
|
|
72
|
+
}
|
|
73
|
+
declare function mountChat(options: MountChatOptions): ChatHandle;
|
|
74
|
+
|
|
75
|
+
export { AppearanceSettings, ChatClient, ChatClientOptions, type ChatHandle, ChatIdentity, ChatPanel, type ChatStrings, ChatTurn, DEFAULT_APPEARANCE, type MessengerAppearance, type MountChatOptions, mountChat, panelStyles };
|
package/dist/chat.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {a as a$1,d}from'./chunk-VG77TYVX.js';import {a}from'./chunk-5XGN7UAV.js';var L="X-Prodantix-Conversation-Token",E="prodantix.chat.handle";function O(){let r=globalThis.localStorage;if(r)return {get:e=>r.getItem(e),remove:e=>r.removeItem(e),set:(e,t)=>r.setItem(e,t)}}var f=class{constructor(e){this.options=e;a(this,"fetchImpl");a(this,"host");a(this,"storage");a(this,"handle");a(this,"identity",null);this.fetchImpl=a$1(e.fetchImpl),this.host=d(e.host),this.storage=e.storage??O(),this.handle=this.readHandle();}get hasThread(){return this.handle!==null}get socketAuth(){return this.handle?{conversationId:this.handle.conversationId,conversationToken:this.handle.token,projectKey:this.options.apiKey}:null}identify(e){this.identity=e;}async ensureThread(e){if(this.handle)return true;let t=await this.request("POST","/v1/conversations",{body:{distinctId:this.options.distinctId,subject:e,userHash:this.identity?.userHash,userId:this.identity?.userId}});return !t?.conversationId||!t.token?false:(this.handle={conversationId:t.conversationId,token:t.token},this.storage?.set(E,JSON.stringify(this.handle)),true)}async send(e){if(!await this.ensureThread())return null;let t=this.handle;return t?(await this.request("POST",`/v1/conversations/${encodeURIComponent(t.conversationId)}/turns`,{body:{body:e},token:t.token}))?.turn??null:null}async load(){let e=this.handle;return e?this.request("GET",`/v1/conversations/${encodeURIComponent(e.conversationId)}`,{token:e.token}):null}readHandle(){let e=this.storage?.get(E);if(!e)return null;try{let t=JSON.parse(e);if(typeof t.conversationId=="string"&&typeof t.token=="string")return {conversationId:t.conversationId,token:t.token}}catch{}return this.storage?.remove(E),null}async request(e,t,n={}){let i=this.fetchImpl;if(!i)return this.options.onError?.(new Error("no fetch available for prodantix chat")),null;let a={authorization:`Bearer ${this.options.apiKey}`,"content-type":"application/json"};n.token&&(a[L]=n.token);try{let s=await i(`${this.host}${t}`,{body:n.body===void 0?void 0:JSON.stringify(n.body),headers:a,method:e}),o=await s.text();return s.ok?o?JSON.parse(o):{}:(this.options.onError?.(new Error(`prodantix chat ${t}: ${s.status}`)),null)}catch(s){return this.options.onError?.(s),null}}};var h={bubbleStyle:"tailed",launcherStyle:"circle_outlined",namePlacement:"avatar_only",skin:"concierge",timestampStyle:"cluster"},H=["concierge","console","quiet"],M=["avatar_circle","circle_filled","circle_outlined","pill_labelled","pill_team","squircle_filled"],$=["hairline","outlined","rounded","tailed"],R=["above","avatar_only","gutter","hidden","inline"],K=["cluster","latency","none","trailing","with_name"],b=(r,e,t)=>typeof r=="string"&&e.includes(r)?r:t;function y(r){let e={bubbleStyle:b(r?.bubbleStyle,$,h.bubbleStyle),launcherStyle:b(r?.launcherStyle,M,h.launcherStyle),namePlacement:b(r?.namePlacement,R,h.namePlacement),skin:b(r?.skin,H,h.skin),timestampStyle:b(r?.timestampStyle,K,h.timestampStyle)};return (e.namePlacement==="avatar_only"||e.namePlacement==="hidden")&&(e.timestampStyle==="with_name"||e.timestampStyle==="latency")&&(e.timestampStyle="trailing"),e.namePlacement==="inline"&&e.bubbleStyle==="hairline"&&(e.namePlacement="above"),e}var F={agentLabel:"Agent",aiLabel:"AI",closeLabel:"Close chat",emptyBody:"We usually reply within a few minutes.",emptyTitle:"Ask us anything.",inputPlaceholder:"Type a message",launcherLabel:"Open support chat",sendLabel:"Send",timeLabel:r=>{let e=new Date(r);return Number.isNaN(e.getTime())?"":`${String(e.getHours()).padStart(2,"0")}:${String(e.getMinutes()).padStart(2,"0")}`},title:"Support",unreadLabel:r=>`${r} unread`},v={accentColor:"#5b5bff",greeting:"",launcherOffsetX:20,launcherOffsetY:20,launcherPosition:"bottom_right",starterPrompts:[],...h},z={concierge:".panel{border-radius:16px;box-shadow:0 16px 40px rgba(0,0,0,.2)}.header{background:var(--a);color:#fff;flex-direction:column;align-items:flex-start;gap:14px;padding:18px 14px 20px 20px}.header h2{font-size:19px;font-weight:640}.composer{padding:12px 12px 14px;gap:8px}.composer input{border:0;background:var(--fill);height:46px;border-radius:23px;padding:0 16px}.composer button{width:46px;min-width:46px;height:46px;padding:0;border-radius:23px}.composer button .sendglyph{display:block}.composer button .sendtext{display:none}",console:".panel{border-radius:12px;box-shadow:0 8px 24px rgba(0,0,0,.16)}.header{background:var(--paper);color:var(--ink);border-bottom:1px solid var(--hairline)}.close{color:var(--ink-2)}",quiet:".composer{position:relative;padding:10px 12px 12px}.composer input{height:42px;padding-right:42px}.composer button{position:absolute;top:50%;right:16px;width:34px;min-width:34px;height:34px;padding:0;background:transparent;color:var(--ink);border-radius:7px;transform:translateY(-50%)}.composer button .sendglyph{display:block;width:18px;height:18px}.composer button .sendtext{display:none}.panel{border-radius:8px;box-shadow:0 2px 8px rgba(0,0,0,.12)}.header{background:var(--paper);color:var(--ink);height:44px;padding:0 8px 0 16px;border-bottom:1px solid var(--hairline)}.header h2{font-size:11px;letter-spacing:.11em;text-transform:uppercase;color:var(--ink-3)}.close{color:var(--ink-2)}"},G={avatar_circle:".launcher{width:60px;height:60px;border-radius:30px;background:var(--paper);border:1px solid var(--hairline);color:var(--ink-2)}",circle_filled:".launcher{width:56px;height:56px;border-radius:28px;background:var(--a);color:#fff}",circle_outlined:".launcher{width:46px;height:46px;border-radius:23px;background:var(--paper);border:1px solid var(--hairline);color:var(--ink-2);box-shadow:0 1px 2px rgba(0,0,0,.08);font-size:21px}.badge{background:var(--a);top:-7px;right:-7px;min-width:19px;height:19px;border-radius:10px;font-size:11.5px}",pill_labelled:".launcher{width:auto;height:52px;border-radius:26px;padding:0 22px;gap:10px;background:var(--a);color:#fff;font-size:14.5px;font-weight:600}",pill_team:".launcher{width:auto;height:54px;border-radius:27px;padding:0 20px 0 8px;gap:10px;background:var(--paper);border:1px solid var(--hairline);color:var(--ink);font-size:14px;font-weight:600}.badge{position:static;background:var(--a)}",squircle_filled:".launcher{width:56px;height:56px;border-radius:16px;background:var(--a);color:#fff}"},B={hairline:".turn{max-width:100%;padding:13px 0;border-top:1px solid var(--hairline);background:none;border-radius:0}.log>.turn:first-child{border-top:0}.turn.end_user{align-self:stretch;display:flex;flex-direction:column;align-items:flex-end}.turn.end_user .body{background:var(--fill);color:var(--ink);border-radius:8px;padding:9px 12px;max-width:85%}",outlined:".turn{background:none;border:1px solid var(--hairline);border-radius:12px}.turn.end_user{background:none;border-color:var(--a);color:var(--ink)}",rounded:".turn{border-radius:18px;padding:10px 15px}",tailed:".turn.agent,.turn.ai{border-radius:12px 12px 12px 4px}.turn.end_user{border-radius:12px 12px 4px 12px}"},D={above:"",avatar_only:".turn.agent,.turn.ai{display:flex;gap:10px;max-width:100%;background:none;padding:0}.turn .body{background:var(--fill);padding:9px 13px;border-radius:inherit}",gutter:".turn.agent,.turn.ai{display:flex;gap:10px;max-width:100%;background:none;padding:0}.turn .body{background:var(--fill);padding:9px 13px;border-radius:inherit}.author{text-transform:none;letter-spacing:0;font-size:12.5px;font-weight:600;opacity:1}",hidden:".turn.agent .author,.turn.ai .author:not(.ai){display:none}",inline:".author{display:inline;margin-right:6px;font-weight:650}"},q={cluster:'.divider{display:flex;align-items:center;gap:10px;margin:0;font-size:11px;opacity:.6}.divider:before,.divider:after{content:"";flex:1;height:1px;background:var(--hairline)}',latency:".stamp{font-size:11px;opacity:.7;margin-left:6px}.lat{font-size:11px;opacity:.7;margin-left:6px}",none:"",trailing:".stamp{display:block;font-size:11px;opacity:.7;margin-top:4px}.turn.end_user .stamp{text-align:right}",with_name:".stamp{font-size:11px;opacity:.7;margin-left:6px}"};function N(r){let e=y(r),t=r.launcherPosition==="bottom_left"?"left":"right",n=r.accentColor;return `${`
|
|
2
|
+
:host {
|
|
3
|
+
all: initial; --a: ${n};
|
|
4
|
+
--paper: #fff; --ink: #0f172a; --ink-3: var(--ink-3);
|
|
5
|
+
--fill: #f1f5f9; --hairline: #e2e8f0; --field: #cbd5e1; --ink-2: rgba(0,0,0,.72);
|
|
6
|
+
color-scheme: light dark;
|
|
7
|
+
}
|
|
8
|
+
@media (prefers-color-scheme: dark) {
|
|
9
|
+
:host {
|
|
10
|
+
--paper: oklch(24.6% 0.015 257); --ink: #fff; --ink-3: rgba(255,255,255,.55);
|
|
11
|
+
--fill: rgba(255,255,255,.06); --hairline: rgba(255,255,255,.13); --field: rgba(255,255,255,.22); --ink-2: rgba(255,255,255,.70);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
* { box-sizing: border-box; font-family: system-ui, sans-serif; }
|
|
15
|
+
.launcher {
|
|
16
|
+
position: fixed; ${t}: ${r.launcherOffsetX}px; bottom: ${r.launcherOffsetY}px; width: 56px; height: 56px;
|
|
17
|
+
border-radius: 28px; border: none; cursor: pointer;
|
|
18
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
19
|
+
background: ${n}; color: #fff; font-size: 24px;
|
|
20
|
+
box-shadow: 0 4px 12px rgba(0,0,0,.2);
|
|
21
|
+
}
|
|
22
|
+
.launcher:focus-visible { outline: 3px solid #0b0e14; outline-offset: 2px; }
|
|
23
|
+
.badge {
|
|
24
|
+
position: absolute; top: -4px; right: -4px; min-width: 20px; height: 20px;
|
|
25
|
+
border-radius: 10px; background: #dc2626; color: #fff; font-size: 12px;
|
|
26
|
+
display: flex; align-items: center; justify-content: center; padding: 0 4px;
|
|
27
|
+
}
|
|
28
|
+
.panel {
|
|
29
|
+
position: fixed; ${t}: ${r.launcherOffsetX}px; bottom: ${r.launcherOffsetY+68}px; width: 360px; max-width: calc(100vw - 40px);
|
|
30
|
+
height: 520px; max-height: calc(100vh - 120px); background: var(--paper); color: var(--ink);
|
|
31
|
+
border-radius: 12px; box-shadow: 0 8px 32px rgba(0,0,0,.24);
|
|
32
|
+
display: flex; flex-direction: column; overflow: hidden;
|
|
33
|
+
}
|
|
34
|
+
.header { padding: 14px 16px; background: #0b0e14; color: #fff; display: flex; align-items: center; justify-content: space-between; }
|
|
35
|
+
.header h2 { margin: 0; font-size: 15px; }
|
|
36
|
+
.close { background: none; border: none; color: #fff; cursor: pointer; font-size: 18px; }
|
|
37
|
+
.close:focus-visible { outline: 2px solid #fff; }
|
|
38
|
+
.log { flex: 1; overflow-y: auto; padding: 12px; display: flex; flex-direction: column; gap: 8px; }
|
|
39
|
+
.turn { max-width: 80%; padding: 8px 12px; border-radius: 12px; font-size: 14px; }
|
|
40
|
+
.turn.end_user { align-self: flex-end; background: ${n}; color: #fff; }
|
|
41
|
+
.turn.agent, .turn.ai { align-self: flex-start; background: var(--fill); color: var(--ink); }
|
|
42
|
+
.author { font-size: 11px; opacity: .7; margin-bottom: 2px; }
|
|
43
|
+
.empty { display: flex; flex-direction: column; gap: 8px; padding: 20px 16px; }
|
|
44
|
+
.empty h3 { margin: 0; font-size: 18px; font-weight: 640; letter-spacing: -.015em; }
|
|
45
|
+
.empty p { margin: 0 0 8px; font-size: 13.5px; color: var(--ink-2); }
|
|
46
|
+
.prompt {
|
|
47
|
+
display: flex; align-items: center; min-height: 44px; padding: 0 14px; text-align: left;
|
|
48
|
+
font-family: inherit; font-size: 13.5px; font-weight: 500; color: var(--ink);
|
|
49
|
+
background: none; border: 1px solid var(--hairline); border-radius: 8px; cursor: pointer;
|
|
50
|
+
}
|
|
51
|
+
.prompt:focus-visible { outline: 2px solid ${n}; outline-offset: 2px; }
|
|
52
|
+
.av { width: 30px; height: 30px; border-radius: 50%; flex: none; display: inline-flex; align-items: center; justify-content: center; font-size: 11.5px; font-weight: 650; color: #fff; background: #7c3f3f; }
|
|
53
|
+
.av.bot { border-radius: 9px; background: var(--fill); color: var(--ink); }
|
|
54
|
+
.composer { display: flex; gap: 8px; padding: 12px; border-top: 1px solid var(--hairline); }
|
|
55
|
+
.composer input { flex: 1; padding: 8px 10px; border: 1px solid var(--field); border-radius: 8px; font-size: 14px; background: transparent; color: var(--ink); }
|
|
56
|
+
.composer input:focus-visible { outline: 2px solid ${n}; }
|
|
57
|
+
.composer button { display: inline-flex; align-items: center; justify-content: center; gap: 0; min-width: 64px; height: 44px; padding: 0 16px; background: ${n}; color: #fff; border: none; border-radius: 8px; cursor: pointer; font-family: inherit; font-size: 14.5px; font-weight: 550; }
|
|
58
|
+
.composer button .sendglyph { display: none; width: 19px; height: 19px; }
|
|
59
|
+
.composer button:focus-visible { outline: 2px solid #0b0e14; }
|
|
60
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
61
|
+
.panel { animation: rise 180ms ease-out; }
|
|
62
|
+
@keyframes rise { from { transform: translateY(8px); opacity: 0; } to { transform: none; opacity: 1; } }
|
|
63
|
+
}
|
|
64
|
+
`}${z[e.skin]}${G[e.launcherStyle]}${B[e.bubbleStyle]}${D[e.namePlacement]}${q[e.timestampStyle]}`}var U=["end_user","agent","ai"],x=class{constructor(e,t,n={},i={}){this.host=e;this.client=t;a(this,"root");a(this,"strings");a(this,"settings");a(this,"appearance");a(this,"launcher");a(this,"badge");a(this,"panel",null);a(this,"lastFocused",null);a(this,"unread",0);this.strings={...F,...n},this.appearance={...v,...i},this.settings=y({...v,...i}),this.root=e.attachShadow({mode:"closed"});let a$1=document.createElement("style");a$1.textContent=N({...v,...i}),this.root.append(a$1),this.launcher=document.createElement("button"),this.launcher.className="launcher",this.launcher.type="button",this.launcher.setAttribute("aria-haspopup","dialog"),this.launcher.setAttribute("aria-label",this.strings.launcherLabel),this.launcher.textContent="\u{1F4AC}",this.launcher.addEventListener("click",()=>this.toggle()),this.badge=document.createElement("span"),this.badge.className="badge",this.badge.hidden=true,this.launcher.append(this.badge),this.root.append(this.launcher);}toggle(){this.panel?this.close():this.open();}async open(){if(this.panel)return;this.lastFocused=this.host.ownerDocument.activeElement,this.unread=0,this.renderBadge();let e=document.createElement("section");e.className="panel",e.setAttribute("role","dialog"),e.setAttribute("aria-modal","true"),e.setAttribute("aria-label",this.strings.title);let t=document.createElement("div");t.className="header";let n=document.createElement("h2");n.textContent=this.strings.title;let i=document.createElement("button");i.className="close",i.type="button",i.setAttribute("aria-label",this.strings.closeLabel),i.textContent="\xD7",i.addEventListener("click",()=>this.close()),t.append(n,i);let a=document.createElement("div");a.className="log",a.setAttribute("role","log"),a.setAttribute("aria-live","polite"),a.setAttribute("aria-label",this.strings.title);let s=document.createElement("form");s.className="composer";let o=document.createElement("input");o.type="text",o.setAttribute("aria-label",this.strings.inputPlaceholder),o.placeholder=this.strings.inputPlaceholder;let p=document.createElement("button");p.type="submit",p.setAttribute("aria-label",this.strings.sendLabel),p.innerHTML='<svg class="sendglyph" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4.5 12 20 4.5 15 20l-3.6-5.4L4.5 12Z"/></svg>';let u=document.createElement("span");u.className="sendtext",u.textContent=this.strings.sendLabel,p.append(u),s.append(o,p),s.addEventListener("submit",g=>{g.preventDefault(),this.submit(o,a);}),e.append(t,a,s),e.addEventListener("keydown",g=>this.onKeydown(g,e,i)),this.root.append(e),this.panel=e,o.focus();let d=await this.client.load();d&&d.turns.length>0?this.renderThread(a,d):this.renderFirstRun(a,o);}renderFirstRun(e,t){let n=document.createElement("div");n.className="empty";let i=document.createElement("h3");i.textContent=this.appearance.greeting.trim()||this.strings.emptyTitle;let a=document.createElement("p");a.textContent=this.strings.emptyBody,n.append(i,a);for(let s of this.appearance.starterPrompts){let o=document.createElement("button");o.className="prompt",o.type="button",o.textContent=s,o.addEventListener("click",()=>{t.value=s,this.submit(t,e);}),n.append(o);}e.replaceChildren(n);}close(){this.panel&&(this.panel.remove(),this.panel=null,this.lastFocused instanceof HTMLElement?this.lastFocused.focus():this.launcher.focus());}onIncomingTurn(e){if(this.panel){let t=this.panel.querySelector(".log");t instanceof HTMLElement&&this.appendTurn(t,e);return}e.authorKind!=="end_user"&&(this.unread+=1,this.renderBadge());}async submit(e,t){let n=e.value.trim();if(!n)return;e.value="",t.querySelector(".empty")?.remove();let i=await this.client.send(n);i&&this.appendTurn(t,i);}renderThread(e,t){e.replaceChildren();for(let n of t.turns)this.appendTurn(e,n);}appendTurn(e,t){e.querySelector(".empty")?.remove();let n=U.includes(t.authorKind)?t.authorKind:"agent",i=this.settings,a=document.createElement("div");if(a.className=`turn ${n}`,n!=="end_user"&&(i.namePlacement==="avatar_only"||i.namePlacement==="gutter")){let d=document.createElement("span");d.className=n==="ai"?"av bot":"av",d.textContent=n==="ai"?this.strings.aiLabel:this.strings.agentLabel.slice(0,2).toUpperCase(),d.setAttribute("aria-hidden","true"),a.append(d);}let o=document.createElement("div");if(o.className="body",n!=="end_user"&&i.namePlacement!=="hidden"&&!(i.namePlacement==="avatar_only"&&n==="agent")||n==="ai"&&i.namePlacement==="hidden"){let d=document.createElement("div");d.className=n==="ai"?"author ai":"author",d.textContent=n==="ai"?this.strings.aiLabel:this.strings.agentLabel,(i.timestampStyle==="with_name"||i.timestampStyle==="latency")&&d.append(this.stamp(t)),o.append(d);}let u=document.createElement("div");u.textContent=t.body,o.append(u),i.timestampStyle==="trailing"&&o.append(this.stamp(t)),a.append(o),e.append(a),e.scrollTop=e.scrollHeight;}stamp(e){let t=document.createElement("span");return t.className="stamp",t.textContent=this.strings.timeLabel(e.createdAt),t}onKeydown(e,t,n){if(e.key==="Escape"){e.preventDefault(),this.close();return}if(e.key!=="Tab")return;let i=t.querySelectorAll('button, input, [tabindex]:not([tabindex="-1"])');if(i.length===0)return;let a=i[0],s=i[i.length-1],o=this.root.activeElement;e.shiftKey&&o===a?(e.preventDefault(),s.focus()):!e.shiftKey&&o===s?(e.preventDefault(),a.focus()):o===null&&(e.preventDefault(),n.focus());}renderBadge(){this.unread>0?(this.badge.hidden=false,this.badge.textContent=String(this.unread),this.launcher.setAttribute("aria-label",`${this.strings.launcherLabel}, ${this.strings.unreadLabel(this.unread)}`)):(this.badge.hidden=true,this.badge.textContent="",this.launcher.setAttribute("aria-label",this.strings.launcherLabel));}};function _(r){return `40${JSON.stringify(r)}`}function I(){return "3"}function P(r){let e=r.charAt(0),t=r.slice(1);if(e==="2")return {kind:"ping"};if(e==="1")return {kind:"disconnect"};if(e==="0"){let s=T(t);return {kind:"open",pingInterval:typeof s?.pingInterval=="number"?s.pingInterval:25e3,pingTimeout:typeof s?.pingTimeout=="number"?s.pingTimeout:2e4}}if(e!=="4")return {kind:"other"};let n=t.charAt(0),i=t.slice(1);if(n==="0")return {kind:"connected"};if(n==="1")return {kind:"disconnect"};if(n==="4"){let s=T(i);return {kind:"connectError",message:typeof s?.message=="string"?s.message:"refused"}}if(n!=="2")return {kind:"other"};let a=T(i);return !Array.isArray(a)||typeof a[0]!="string"?{kind:"other"}:{kind:"event",name:a[0],payload:a[1]}}function T(r){try{return JSON.parse(r)}catch{return null}}var j="/socket.io/?EIO=4&transport=websocket",k=class{constructor(e){this.options=e;a(this,"socket",null);a(this,"heartbeat",null);a(this,"ready",false);a(this,"closed",false);a(this,"heartbeatWindow",45e3);a(this,"factory");a(this,"setTimer");a(this,"clearTimer");this.factory=e.socketFactory??W,this.setTimer=e.setTimer??((t,n)=>setTimeout(t,n)),this.clearTimer=e.clearTimer??(t=>clearTimeout(t));}open(){if(this.socket||this.closed)return;let e=`${this.options.host.replace(/^http/,"ws").replace(/\/+$/,"")}${j}`,t;try{t=this.factory(e);}catch{this.options.onClosed(false);return}this.socket=t,t.onmessage=n=>this.receive(String(n.data)),t.onerror=()=>t.close(),t.onclose=()=>this.fell();}close(){this.closed=true,this.stopHeartbeat();let e=this.socket;this.socket=null,e?.close();}receive(e){let t=P(e);if(t.kind==="open"){this.armHeartbeat(t.pingInterval+t.pingTimeout),this.socket?.send(_(this.options.auth));return}if(t.kind==="ping"){this.armHeartbeat(),this.socket?.send(I());return}if(t.kind==="connectError"||t.kind==="disconnect"){this.stopHeartbeat(),this.socket?.close();return}if(t.kind==="event"){if(t.name==="ready"){this.ready=true,this.options.onReady();return}if(t.name==="conversation.turn"){let n=t.payload?.turn;n&&this.options.onTurn(n);}}}fell(){this.stopHeartbeat();let e=this.ready;this.socket=null,this.ready=false,this.closed||this.options.onClosed(e);}armHeartbeat(e){e!==void 0&&(this.heartbeatWindow=e),this.stopHeartbeat(),this.heartbeat=this.setTimer(()=>this.socket?.close(),this.heartbeatWindow);}stopHeartbeat(){this.heartbeat!==null&&this.clearTimer(this.heartbeat),this.heartbeat=null;}};function W(r){let e=globalThis.WebSocket;if(!e)throw new Error("no WebSocket");return new e(r)}function le(r){let e=globalThis.document;if(!e)throw new Error("prodantix chat requires a document; mount it in the browser");let t=r.mountPoint??e.createElement("div");r.mountPoint||e.body.append(t);let n=new f(r),i=new x(t,n,r.strings,r.appearance),a=new Set,s,o=null,p=r.pollIntervalMs??15e3,u=c=>{a.has(c.id)||c.authorKind==="end_user"||(a.add(c.id),i.onIncomingTurn(c));},d=async()=>{if(!n.hasThread)return;let c=await n.load();if(c){for(let m of c.turns)u(m);a=new Set(c.turns.map(m=>m.id));}},g=()=>{s||p<=0||(s=setInterval(()=>void d(),p));},C=()=>{s&&clearInterval(s),s=void 0;},S=()=>{if(o||!r.socketHost)return;let c=n.socketAuth;c&&(o=new k({auth:c,host:r.socketHost,onClosed:m=>{o=null,g(),m&&S();},onReady:C,onTurn:u,socketFactory:r.socketFactory}),o.open());};return g(),S(),{close:()=>i.close(),destroy:()=>{C(),o?.close(),o=null,i.close(),t.remove();},identify:c=>n.identify(c),open:()=>{i.open().then(S);}}}export{f as ChatClient,x as ChatPanel,v as DEFAULT_APPEARANCE,h as DEFAULT_APPEARANCE_SETTINGS,le as mountChat,N as panelStyles,y as resolveAppearance};//# sourceMappingURL=chat.js.map
|
|
65
|
+
//# sourceMappingURL=chat.js.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import {a as a$1,d,b as b$1,c as c$1}from'./chunk-VG77TYVX.js';import {a}from'./chunk-5XGN7UAV.js';var c=class extends Error{constructor(s,r,n){super(r,n);a(this,"code");this.code=s,this.name="ProdantixError";}},y=class extends c{constructor(e){super("config",e),this.name="ConfigError";}},m=class extends c{constructor(s,r){super("validation",r);a(this,"field");this.field=s,this.name="ValidationError";}},l=class extends c{constructor(s,r,n){super("transport",s,n);a(this,"status");this.status=r,this.name="TransportError";}};var g=class{constructor(){a(this,"store",new Map);}getItem(e){return this.store.get(e)??null}removeItem(e){this.store.delete(e);}setItem(e,s){this.store.set(e,s);}};function ae(){try{let t=globalThis.localStorage;if(t){let e="__pdx_probe__";return t.setItem(e,"1"),t.removeItem(e),t}}catch{return new g}return new g}var _="prodantix-js",C="0.0.1";var h=Symbol("absent");function U(t,e){if(t==="distinct_id")return e.distinctId;let s=e.properties??{};if(Object.prototype.hasOwnProperty.call(s,t))return s[t];let r=e.attributes??{};return Object.prototype.hasOwnProperty.call(r,t)?r[t]:h}function p(t){return t===h?"undefined":String(t)}function R(t){return t===h?Number.NaN:Number(t)}function $(t){return t!==h&&t!==null&&t!==""}function M(t,e){if(!Array.isArray(e))return false;let s=p(t);return e.map(r=>String(r)).includes(s)}function k(t,e){let s=U(t.attribute,e),r=t.value;switch(t.op){case "is_set":return $(s);case "is_not_set":return !$(s);case "eq":return p(s)===p(r===void 0?h:r);case "neq":return p(s)!==p(r===void 0?h:r);case "contains":return p(s).includes(p(r===void 0?h:r));case "in":return M(s,r);case "not_in":return Array.isArray(r)?!M(s,r):false;case "gt":return v(s,r,(n,o)=>n>o);case "gte":return v(s,r,(n,o)=>n>=o);case "lt":return v(s,r,(n,o)=>n<o);case "lte":return v(s,r,(n,o)=>n<=o);default:return false}}function v(t,e,s){let r=R(t),n=e===void 0?Number.NaN:R(e);return Number.isNaN(r)||Number.isNaN(n)?false:s(r,n)}function q(t,e){let s=`${t}:${e}`,r=2166136261;for(let n=0;n<s.length;n++)r^=s.charCodeAt(n),r=Math.imul(r,16777619);return (r>>>0)%100}function B(t,e){return t.enabled?t.targeting.length>0&&!t.targeting.every(s=>k(s,e))?{enabled:false,reason:"targeting"}:t.rolloutPercentage>=100?{enabled:true,reason:"rollout_full"}:q(t.key,e.distinctId)<t.rolloutPercentage?{enabled:true,reason:"rollout"}:{enabled:false,reason:"rollout_excluded"}:{enabled:false,reason:"disabled"}}function A(t,e){let s={};for(let r of t)s[r.key]=B(r,e).enabled;return s}function H(t,e){let s=t.variations??[],r=s[0];if(!r)return null;if(!t.enabled||t.targeting.length>0&&!t.targeting.every(a=>k(a,e)))return r;let n=q(t.key,e.distinctId),o=0;for(let a=s.length-1;a>=0;a--)if(o+=s[a].weight,n<o)return s[a];return r}function he(t,e,s){let r=t.find(n=>n.key===e);return r?H(r,s)?.value??null:null}var x=class{constructor(e){a(this,"fetch");a(this,"host");a(this,"projectKey");a(this,"requestTimeoutMs");this.fetch=a$1(e.fetch),this.host=d(e.host),this.projectKey=e.projectKey,this.requestTimeoutMs=e.requestTimeoutMs??1e4;}async fetchAll(e){let s=this.fetch;if(!s)throw new l("no fetch implementation available in this runtime");let r=`${this.host}/v1/flags?distinct_id=${encodeURIComponent(e)}`,n=b$1(),o=n?setTimeout(()=>n.abort(),this.requestTimeoutMs):void 0;try{let a=await s(r,{headers:{authorization:`Bearer ${this.projectKey}`},method:"GET",signal:n?.signal});if(!a.ok)throw new l(`flags request failed with status ${a.status}`,a.status);return JSON.parse(await a.text()).flags??{}}finally{o!==void 0&&clearTimeout(o);}}async snapshot(){let e=this.fetch;if(!e)throw new l("no fetch implementation available in this runtime");let s=`${this.host}/v1/flags/snapshot`,r=b$1(),n=r?setTimeout(()=>r.abort(),this.requestTimeoutMs):void 0;try{let o=await e(s,{headers:{authorization:`Bearer ${this.projectKey}`},method:"GET",signal:r?.signal});if(!o.ok)throw new l(`flag snapshot request failed with status ${o.status}`,o.status);let a=JSON.parse(await o.text());return {flags:a.flags??[],generatedAt:a.generatedAt}}finally{n!==void 0&&clearTimeout(n);}}};var b=class{constructor(e){a(this,"fetch");a(this,"host");a(this,"projectKey");a(this,"requestTimeoutMs");this.fetch=a$1(e.fetch),this.host=d(e.host),this.projectKey=e.projectKey,this.requestTimeoutMs=e.requestTimeoutMs??1e4;}async inbox(e){let s=this.requireFetch(),r=`${this.host}/v1/messages?distinct_id=${encodeURIComponent(e)}`,n=await this.request(s,r,{headers:this.authHeaders(),method:"GET"});if(!n.ok)throw new l(`inbox request failed with status ${n.status}`,n.status);return JSON.parse(await n.text()).messages??[]}async markRead(e,s){let r=this.requireFetch(),n=`${this.host}/v1/messages/read`,o=await this.request(r,n,{body:JSON.stringify({distinct_id:s,message_id:e}),headers:{...this.authHeaders(),"content-type":"application/json"},method:"POST"});if(!o.ok)throw new l(`mark-read request failed with status ${o.status}`,o.status)}requireFetch(){if(!this.fetch)throw new l("no fetch implementation available in this runtime");return this.fetch}authHeaders(){return {authorization:`Bearer ${this.projectKey}`}}async request(e,s,r){let n=b$1(),o=n?setTimeout(()=>n.abort(),this.requestTimeoutMs):void 0;try{return await e(s,{...r,signal:n?.signal})}finally{o!==void 0&&clearTimeout(o);}}};function N(t){return t>=400&&t<500&&t!==429}var I=class{constructor(e={}){a(this,"fetch");a(this,"maxRetries");a(this,"requestTimeoutMs");a(this,"baseDelayMs");a(this,"maxDelayMs");a(this,"sleep");a(this,"random");this.fetch=a$1(e.fetch),this.maxRetries=e.maxRetries??3,this.requestTimeoutMs=e.requestTimeoutMs??1e4,this.baseDelayMs=e.baseDelayMs??500,this.maxDelayMs=e.maxDelayMs??3e4,this.sleep=e.sleep??c$1,this.random=e.random??Math.random;}async send(e){let s=this.fetch;if(!s)throw new l("no fetch implementation available in this runtime");let r=JSON.stringify(e.body),n;for(let o=0;o<=this.maxRetries;o+=1){try{let a=await this.attempt(s,e,r);if(a.ok)return;if(N(a.status))throw new l(`ingest rejected batch with status ${a.status}`,a.status);n=new l(`ingest transient status ${a.status}`,a.status);}catch(a){if(a instanceof l&&a.status!==void 0&&N(a.status))throw a;n=a;}o<this.maxRetries&&await this.sleep(this.backoff(o));}throw new l("ingest delivery failed after retries",void 0,{cause:n})}async attempt(e,s,r){let n=b$1(),o=n?setTimeout(()=>n.abort(),this.requestTimeoutMs):void 0;try{return await e(s.url,{body:r,headers:{authorization:`Bearer ${s.projectKey}`,"content-type":"application/json"},method:"POST",signal:n?.signal})}finally{o!==void 0&&clearTimeout(o);}}backoff(e){return Math.min(this.maxDelayMs,this.baseDelayMs*2**e)+this.random()*this.baseDelayMs}};var O={now:()=>new Date};function E(t){return t.toISOString()}function G(){return globalThis.crypto}function X(t){t[6]=t[6]&15|64,t[8]=t[8]&63|128;let e=[];for(let s=0;s<16;s+=1)e.push(t[s].toString(16).padStart(2,"0"));return `${e[0]}${e[1]}${e[2]}${e[3]}-${e[4]}${e[5]}-${e[6]}${e[7]}-${e[8]}${e[9]}-${e[10]}${e[11]}${e[12]}${e[13]}${e[14]}${e[15]}`}function Y(){let t=G();if(t?.randomUUID)return t.randomUUID();let e=new Uint8Array(16);if(t?.getRandomValues)t.getRandomValues(e);else for(let s=0;s<16;s+=1)e[s]=Math.floor(Math.random()*256);return X(e)}var D={uuid:Y};var Z=/^pdx_pub_(?:(?:live|test)_)?[a-z0-9]{32}$/;var W=/^(?:\$|[a-z])[a-z0-9_.]*$/;function K(t){let e=0;for(let s of t)e+=1;return e}function L(t){return Z.test(t)}function ee(t){return W.test(t)}function j(t){let e=K(t);if(e<1||e>200)throw new m("distinct_id","distinct_id must be between 1 and 200 characters")}function V(t){let e=K(t);if(e<1||e>200)throw new m("event_name","event_name must be between 1 and 200 characters");if(!ee(t))throw new m("event_name","event_name must match /^(\\$|[a-z])[a-z0-9_.]*$/")}var te=t=>{};function z(t){if(!t.apiKey||!L(t.apiKey))throw new y("apiKey must be a public project key of the form pdx_pub_<32 lowercase alphanumerics>");if(!t.host)throw new y("host is required (the ingest base URL)");let e=d(t.host),s=t.defaultProperties;return {apiKey:t.apiKey,autocapture:t.autocapture??false,clock:t.clock??O,defaultProperties:typeof s=="function"?s:()=>s??{},flagsHost:t.flagsHost?d(t.flagsHost):e,flushAt:t.flushAt??20,flushIntervalMs:t.flushIntervalMs??1e4,host:e,ids:t.ids??D,locale:t.locale,maxQueueSize:t.maxQueueSize??1e3,maxRetries:t.maxRetries??3,namespace:t.apiKey.slice(0,16),onError:t.onError??te,os:t.os,requestTimeoutMs:t.requestTimeoutMs??1e4,sdkName:t.sdkName??_,sdkVersion:t.sdkVersion??C,storage:t.storage??new g,transport:t.transport}}function J(t,e,s){V(t.eventName),j(t.distinctId);let r={distinct_id:t.distinctId,event_id:t.eventId??s.uuid(),event_name:t.eventName,properties:t.properties??{},schema_version:1,timestamp:E(t.timestamp??e.now())};return t.context&&(r.context=t.context),t.sessionId&&(r.session_id=t.sessionId),r}var w=class{constructor(e,s,r){this.storage=e;this.ids=s;this.namespace=r;a(this,"anonymousId");a(this,"distinctId");a(this,"identified");let n=e.getItem(this.key("anonymous_id"));n?this.anonymousId=n:(this.anonymousId=s.uuid(),e.setItem(this.key("anonymous_id"),this.anonymousId));let o=e.getItem(this.key("distinct_id"));o?(this.distinctId=o,this.identified=true):(this.distinctId=this.anonymousId,this.identified=false);}getAnonymousId(){return this.anonymousId}getDistinctId(){return this.distinctId}isIdentified(){return this.identified}snapshot(){return {anonymousId:this.anonymousId,distinctId:this.distinctId,identified:this.identified}}identify(e){return this.identified&&this.distinctId===e?{changed:false}:(this.distinctId=e,this.identified=true,this.storage.setItem(this.key("distinct_id"),e),{changed:true})}reset(){this.anonymousId=this.ids.uuid(),this.distinctId=this.anonymousId,this.identified=false,this.storage.setItem(this.key("anonymous_id"),this.anonymousId),this.storage.removeItem(this.key("distinct_id"));}key(e){return `pdx.${this.namespace}.${e}`}};var F=class{constructor(e,s){this.maxSize=e;this.onOverflow=s;a(this,"events",[]);}get size(){return this.events.length}enqueue(e){this.events.push(e),this.enforceCap();}restore(e){this.events.push(...e),this.enforceCap();}requeue(e){this.events.unshift(...e),this.enforceCap();}drain(e){let s=e===void 0?this.events.length:Math.min(e,this.events.length);return this.events.splice(0,s)}snapshot(){return [...this.events]}enforceCap(){if(this.events.length<=this.maxSize)return;let e=this.events.splice(0,this.events.length-this.maxSize);this.onOverflow?.({dropped:e});}};var se="queue",re=1e3,ne=3e4,Q=t=>{let e={};return t.avatar!==void 0&&(e.$avatar=t.avatar),t.email!==void 0&&(e.$email=t.email),t.name!==void 0&&(e.$name=t.name),t.phone!==void 0&&(e.$phone=t.phone),e},S=class{constructor(e){a(this,"config");a(this,"identity");a(this,"queue");a(this,"transport");a(this,"flagsClient");a(this,"messagesClient");a(this,"context");a(this,"flushTimer");a(this,"flushing",false);a(this,"cachedFlags");a(this,"cachedSnapshot");this.config=z(e),this.identity=new w(this.config.storage,this.config.ids,this.config.namespace),this.queue=new F(this.config.maxQueueSize,({dropped:s})=>{this.config.onError(new c("queue_overflow",`event queue overflow: dropped ${s.length} oldest event(s)`));}),this.transport=this.config.transport??new I({maxRetries:this.config.maxRetries,requestTimeoutMs:this.config.requestTimeoutMs}),this.flagsClient=new x({host:this.config.flagsHost,projectKey:this.config.apiKey,requestTimeoutMs:this.config.requestTimeoutMs}),this.messagesClient=new b({host:this.config.flagsHost,projectKey:this.config.apiKey,requestTimeoutMs:this.config.requestTimeoutMs}),this.context={sdk:this.config.sdkName,sdk_version:this.config.sdkVersion},this.config.os&&(this.context.os=this.config.os),this.config.locale&&(this.context.locale=this.config.locale),this.restoreQueue(),this.startTimer();}get distinctId(){return this.identity.getDistinctId()}get anonymousId(){return this.identity.getAnonymousId()}capture(e,s={}){try{let r={...this.config.defaultProperties(),...s.properties??{}},n=J({context:this.context,distinctId:this.identity.getDistinctId(),eventName:e,properties:r,sessionId:s.sessionId,timestamp:s.timestamp},this.config.clock,this.config.ids);this.enqueue(n);}catch(r){this.config.onError(r);}}identify(e,s={}){let r=this.identity.getAnonymousId(),n=!this.identity.isIdentified(),o=this.identity.identify(e),a={};n&&o.changed&&(a.$anon_distinct_id=r);let T={...Q(s.traits??{}),...s.set??{}};Object.keys(T).length>0&&(a.$set=T),this.capture("$identify",{properties:a});}alias(e){this.capture("$create_alias",{properties:{alias:e}});}group(e,s,r){let n={$group_key:s,$group_type:e};r&&(n.$set=r),this.capture("$group",{properties:n});}setPersonProperties(e,s){let r={};e&&(r.$set=e),s&&(r.$set_once=s),this.capture("$set",{properties:r});}setPersonTraits(e){let s=Q(e);Object.keys(s).length!==0&&this.capture("$set",{properties:{$set:s}});}async getAllFlags(){let e=this.identity.getDistinctId(),s=await this.flagsClient.fetchAll(e);return this.cachedFlags={distinctId:e,flags:s},s}async isFeatureEnabled(e){return (await this.getAllFlags())[e]??false}getCachedFlag(e){if(!(!this.cachedFlags||this.cachedFlags.distinctId!==this.distinctId))return this.cachedFlags.flags[e]}async getLocalFlags(e={}){let s=await this.flagSnapshot();return A(s.flags,{attributes:e.attributes,distinctId:this.identity.getDistinctId(),properties:e.properties})}async isFeatureEnabledLocal(e,s){return (await this.getLocalFlags(s))[e]??false}async flagSnapshot(){let e=this.config.clock.now().getTime();if(this.cachedSnapshot&&e-this.cachedSnapshot.fetchedAt<ne)return this.cachedSnapshot.snapshot;let s=await this.flagsClient.snapshot();return this.cachedSnapshot={fetchedAt:e,snapshot:s},s}async getInbox(){return this.messagesClient.inbox(this.identity.getDistinctId())}async markMessageRead(e){await this.messagesClient.markRead(e,this.identity.getDistinctId());}async flush(){if(this.flushing||this.queue.size===0)return;this.flushing=true;let e=this.queue.drain(re);try{await this.transport.send({body:{events:e,sent_at:E(this.config.clock.now())},projectKey:this.config.apiKey,url:`${this.config.host}/v1/events`}),this.persistQueue();}catch(s){this.queue.requeue(e),this.persistQueue(),this.config.onError(s);}finally{this.flushing=false;}}reset(){this.identity.reset(),this.cachedFlags=void 0,this.cachedSnapshot=void 0;}async shutdown(){this.stopTimer(),await this.flush();}enqueue(e){this.queue.enqueue(e),this.persistQueue(),this.queue.size>=this.config.flushAt&&this.flush();}persistQueue(){try{this.config.storage.setItem(this.persistKey(),JSON.stringify(this.queue.snapshot()));}catch(e){this.config.onError(e);}}restoreQueue(){try{let e=this.config.storage.getItem(this.persistKey());if(!e)return;let s=JSON.parse(e);Array.isArray(s)&&this.queue.restore(s);}catch(e){this.config.onError(e);}}startTimer(){if(this.config.flushIntervalMs<=0)return;let e=setInterval(()=>{this.flush();},this.config.flushIntervalMs),s=e;typeof s.unref=="function"&&s.unref(),this.flushTimer=e;}stopTimer(){this.flushTimer!==void 0&&(clearInterval(this.flushTimer),this.flushTimer=void 0);}persistKey(){return `pdx.${this.config.namespace}.${se}`}};function st(t){return new S(t)}export{c as a,y as b,m as c,l as d,g as e,ae as f,Y as g,_ as h,C as i,k as j,q as k,B as l,A as m,H as n,he as o,x as p,b as q,I as r,S as s,st as t};//# sourceMappingURL=chunk-7J6AQICL.js.map
|
|
2
|
+
//# sourceMappingURL=chunk-7J6AQICL.js.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function r(e){if(e)return e;let t=globalThis.fetch;if(typeof t=="function")return t.bind(globalThis)}function n(){let e=globalThis.AbortController;return e?new e:void 0}var o=e=>new Promise(t=>{setTimeout(t,e);});function i(e){return e.replace(/\/+$/,"")}export{r as a,n as b,o as c,i as d};//# sourceMappingURL=chunk-VG77TYVX.js.map
|
|
2
|
+
//# sourceMappingURL=chunk-VG77TYVX.js.map
|
|
@@ -87,8 +87,27 @@ interface CaptureOptions {
|
|
|
87
87
|
sessionId?: string;
|
|
88
88
|
timestamp?: Date;
|
|
89
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* The profile keys the platform itself understands.
|
|
92
|
+
*
|
|
93
|
+
* They are ordinary properties on the wire; the only thing that makes them
|
|
94
|
+
* special is the `$` prefix, which is how this platform marks a name it owns
|
|
95
|
+
* rather than one the caller chose. Passing them through `traits` means never
|
|
96
|
+
* having to remember whether the console reads `email` or `$email`: an
|
|
97
|
+
* unprefixed `email` is a property of your own and stays one, and would never
|
|
98
|
+
* reach the Email column.
|
|
99
|
+
*/
|
|
100
|
+
interface PersonTraits {
|
|
101
|
+
avatar?: string;
|
|
102
|
+
email?: string;
|
|
103
|
+
name?: string;
|
|
104
|
+
phone?: string;
|
|
105
|
+
}
|
|
90
106
|
interface IdentifyOptions {
|
|
107
|
+
/** Arbitrary profile properties your own code defines. */
|
|
91
108
|
set?: EventProperties;
|
|
109
|
+
/** The reserved traits the console renders as fields. */
|
|
110
|
+
traits?: PersonTraits;
|
|
92
111
|
}
|
|
93
112
|
declare class ProdantixClient {
|
|
94
113
|
private readonly config;
|
|
@@ -110,6 +129,14 @@ declare class ProdantixClient {
|
|
|
110
129
|
alias(alias: string): void;
|
|
111
130
|
group(groupType: string, groupKey: string, properties?: EventProperties): void;
|
|
112
131
|
setPersonProperties(set?: EventProperties, setOnce?: EventProperties): void;
|
|
132
|
+
/**
|
|
133
|
+
* Attach the reserved traits to whoever is current, without an identify.
|
|
134
|
+
*
|
|
135
|
+
* This does NOT make the person identified: only `identify()` does that, so a
|
|
136
|
+
* trait set on an anonymous visitor leaves them anonymous and carrying an
|
|
137
|
+
* address, which is exactly what a newsletter signup before login looks like.
|
|
138
|
+
*/
|
|
139
|
+
setPersonTraits(traits: PersonTraits): void;
|
|
113
140
|
getAllFlags(): Promise<Record<string, boolean>>;
|
|
114
141
|
isFeatureEnabled(key: string): Promise<boolean>;
|
|
115
142
|
getCachedFlag(key: string): boolean | undefined;
|
|
@@ -130,4 +157,4 @@ declare class ProdantixClient {
|
|
|
130
157
|
}
|
|
131
158
|
declare function createClient(config: ProdantixConfig): ProdantixClient;
|
|
132
159
|
|
|
133
|
-
export { type CaptureOptions as C, type EventBatch as E, type FlagsResponse as F, type
|
|
160
|
+
export { type CaptureOptions as C, type EventBatch as E, type FlagsResponse as F, type InboxMessage as I, type JsonValue as J, type LocalFlagContext as L, ProdantixClient as P, type StorageAdapter as S, type Transport as T, type Clock as a, type EventContext as b, type EventEnvelope as c, type EventProperties as d, type IdFactory as e, type IdentifyOptions as f, type InboxResponse as g, type ProdantixConfig as h, type TransportRequest as i, createClient as j };
|
|
@@ -87,8 +87,27 @@ interface CaptureOptions {
|
|
|
87
87
|
sessionId?: string;
|
|
88
88
|
timestamp?: Date;
|
|
89
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* The profile keys the platform itself understands.
|
|
92
|
+
*
|
|
93
|
+
* They are ordinary properties on the wire; the only thing that makes them
|
|
94
|
+
* special is the `$` prefix, which is how this platform marks a name it owns
|
|
95
|
+
* rather than one the caller chose. Passing them through `traits` means never
|
|
96
|
+
* having to remember whether the console reads `email` or `$email`: an
|
|
97
|
+
* unprefixed `email` is a property of your own and stays one, and would never
|
|
98
|
+
* reach the Email column.
|
|
99
|
+
*/
|
|
100
|
+
interface PersonTraits {
|
|
101
|
+
avatar?: string;
|
|
102
|
+
email?: string;
|
|
103
|
+
name?: string;
|
|
104
|
+
phone?: string;
|
|
105
|
+
}
|
|
90
106
|
interface IdentifyOptions {
|
|
107
|
+
/** Arbitrary profile properties your own code defines. */
|
|
91
108
|
set?: EventProperties;
|
|
109
|
+
/** The reserved traits the console renders as fields. */
|
|
110
|
+
traits?: PersonTraits;
|
|
92
111
|
}
|
|
93
112
|
declare class ProdantixClient {
|
|
94
113
|
private readonly config;
|
|
@@ -110,6 +129,14 @@ declare class ProdantixClient {
|
|
|
110
129
|
alias(alias: string): void;
|
|
111
130
|
group(groupType: string, groupKey: string, properties?: EventProperties): void;
|
|
112
131
|
setPersonProperties(set?: EventProperties, setOnce?: EventProperties): void;
|
|
132
|
+
/**
|
|
133
|
+
* Attach the reserved traits to whoever is current, without an identify.
|
|
134
|
+
*
|
|
135
|
+
* This does NOT make the person identified: only `identify()` does that, so a
|
|
136
|
+
* trait set on an anonymous visitor leaves them anonymous and carrying an
|
|
137
|
+
* address, which is exactly what a newsletter signup before login looks like.
|
|
138
|
+
*/
|
|
139
|
+
setPersonTraits(traits: PersonTraits): void;
|
|
113
140
|
getAllFlags(): Promise<Record<string, boolean>>;
|
|
114
141
|
isFeatureEnabled(key: string): Promise<boolean>;
|
|
115
142
|
getCachedFlag(key: string): boolean | undefined;
|
|
@@ -130,4 +157,4 @@ declare class ProdantixClient {
|
|
|
130
157
|
}
|
|
131
158
|
declare function createClient(config: ProdantixConfig): ProdantixClient;
|
|
132
159
|
|
|
133
|
-
export { type CaptureOptions as C, type EventBatch as E, type FlagsResponse as F, type
|
|
160
|
+
export { type CaptureOptions as C, type EventBatch as E, type FlagsResponse as F, type InboxMessage as I, type JsonValue as J, type LocalFlagContext as L, ProdantixClient as P, type StorageAdapter as S, type Transport as T, type Clock as a, type EventContext as b, type EventEnvelope as c, type EventProperties as d, type IdFactory as e, type IdentifyOptions as f, type InboxResponse as g, type ProdantixConfig as h, type TransportRequest as i, createClient as j };
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { F as FetchLike } from './http-BCh716Vs.js';
|
|
2
|
+
|
|
3
|
+
interface ChatTurn {
|
|
4
|
+
id: string;
|
|
5
|
+
authorKind: 'end_user' | 'agent' | 'ai';
|
|
6
|
+
authorId: string | null;
|
|
7
|
+
body: string;
|
|
8
|
+
createdAt: string;
|
|
9
|
+
}
|
|
10
|
+
interface ChatThread {
|
|
11
|
+
id: string;
|
|
12
|
+
status: string;
|
|
13
|
+
turns: ChatTurn[];
|
|
14
|
+
}
|
|
15
|
+
interface ChatClientOptions {
|
|
16
|
+
apiKey: string;
|
|
17
|
+
host: string;
|
|
18
|
+
distinctId: string;
|
|
19
|
+
storage?: ChatStorage;
|
|
20
|
+
fetchImpl?: FetchLike;
|
|
21
|
+
onError?: (error: unknown) => void;
|
|
22
|
+
}
|
|
23
|
+
interface ChatIdentity {
|
|
24
|
+
userId: string;
|
|
25
|
+
userHash: string;
|
|
26
|
+
}
|
|
27
|
+
interface ChatStorage {
|
|
28
|
+
get(key: string): string | null;
|
|
29
|
+
set(key: string, value: string): void;
|
|
30
|
+
remove(key: string): void;
|
|
31
|
+
}
|
|
32
|
+
declare class ChatClient {
|
|
33
|
+
private readonly options;
|
|
34
|
+
private readonly fetchImpl?;
|
|
35
|
+
private readonly host;
|
|
36
|
+
private readonly storage?;
|
|
37
|
+
private handle;
|
|
38
|
+
private identity;
|
|
39
|
+
constructor(options: ChatClientOptions);
|
|
40
|
+
get hasThread(): boolean;
|
|
41
|
+
get socketAuth(): {
|
|
42
|
+
conversationId: string;
|
|
43
|
+
conversationToken: string;
|
|
44
|
+
projectKey: string;
|
|
45
|
+
} | null;
|
|
46
|
+
identify(identity: ChatIdentity): void;
|
|
47
|
+
ensureThread(subject?: string): Promise<boolean>;
|
|
48
|
+
send(body: string): Promise<ChatTurn | null>;
|
|
49
|
+
load(): Promise<ChatThread | null>;
|
|
50
|
+
private readHandle;
|
|
51
|
+
private request;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
type MessengerSkin = 'concierge' | 'console' | 'quiet';
|
|
55
|
+
type LauncherStyle = 'avatar_circle' | 'circle_filled' | 'circle_outlined' | 'pill_labelled' | 'pill_team' | 'squircle_filled';
|
|
56
|
+
type BubbleStyle = 'hairline' | 'outlined' | 'rounded' | 'tailed';
|
|
57
|
+
type NamePlacement = 'above' | 'avatar_only' | 'gutter' | 'hidden' | 'inline';
|
|
58
|
+
type TimestampStyle = 'cluster' | 'latency' | 'none' | 'trailing' | 'with_name';
|
|
59
|
+
interface AppearanceSettings {
|
|
60
|
+
bubbleStyle: BubbleStyle;
|
|
61
|
+
launcherStyle: LauncherStyle;
|
|
62
|
+
namePlacement: NamePlacement;
|
|
63
|
+
skin: MessengerSkin;
|
|
64
|
+
timestampStyle: TimestampStyle;
|
|
65
|
+
}
|
|
66
|
+
declare const DEFAULT_APPEARANCE_SETTINGS: AppearanceSettings;
|
|
67
|
+
declare function resolveAppearance(config: Partial<AppearanceSettings> | null | undefined): AppearanceSettings;
|
|
68
|
+
|
|
69
|
+
interface MessengerConfig extends AppearanceSettings {
|
|
70
|
+
enabled: boolean;
|
|
71
|
+
launcherPosition: 'bottom_left' | 'bottom_right';
|
|
72
|
+
launcherOffsetX: number;
|
|
73
|
+
launcherOffsetY: number;
|
|
74
|
+
accentColor: string;
|
|
75
|
+
greeting: string;
|
|
76
|
+
awayMessage: string;
|
|
77
|
+
availability: unknown;
|
|
78
|
+
version: string;
|
|
79
|
+
starterPrompts: string[];
|
|
80
|
+
socketUrl: string;
|
|
81
|
+
}
|
|
82
|
+
interface MessengerConfigOptions {
|
|
83
|
+
apiKey: string;
|
|
84
|
+
host: string;
|
|
85
|
+
locale?: string;
|
|
86
|
+
storage?: ChatStorage;
|
|
87
|
+
fetchImpl?: FetchLike;
|
|
88
|
+
onError?: (error: unknown) => void;
|
|
89
|
+
}
|
|
90
|
+
declare const MESSENGER_CACHE_KEY = "prodantix.messenger.config";
|
|
91
|
+
declare function cachedMessengerConfig(storage: ChatStorage | undefined, apiKey: string): MessengerConfig | null;
|
|
92
|
+
declare function fetchMessengerConfig(options: MessengerConfigOptions): Promise<MessengerConfig | null>;
|
|
93
|
+
|
|
94
|
+
export { type AppearanceSettings as A, type BubbleStyle as B, ChatClient as C, DEFAULT_APPEARANCE_SETTINGS as D, type LauncherStyle as L, type MessengerConfig as M, type NamePlacement as N, type TimestampStyle as T, type ChatTurn as a, type ChatIdentity as b, type ChatClientOptions as c, type ChatStorage as d, type ChatThread as e, type MessengerSkin as f, MESSENGER_CACHE_KEY as g, type MessengerConfigOptions as h, cachedMessengerConfig as i, fetchMessengerConfig as j, resolveAppearance as r };
|