@thisispamela/widget 1.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 ADDED
@@ -0,0 +1,133 @@
1
+ # @thisispamela/widget
2
+
3
+ Embeddable Pamela Voice AI widget for any website. Add AI-powered phone calls with a single script tag.
4
+
5
+ ## Installation
6
+
7
+ ### Script tag (CDN)
8
+
9
+ **Primary CDN (when available):**
10
+ ```html
11
+ <script src="https://cdn.thisispamela.com/widget.js"></script>
12
+ ```
13
+
14
+ **unpkg / jsDelivr (npm-backed):**
15
+ ```html
16
+ <script src="https://unpkg.com/@thisispamela/widget"></script>
17
+ <!-- or -->
18
+ <script src="https://cdn.jsdelivr.net/npm/@thisispamela/widget"></script>
19
+ ```
20
+
21
+ Example:
22
+ ```html
23
+ <script src="https://cdn.thisispamela.com/widget.js"></script>
24
+ <script>
25
+ Pamela.init({
26
+ apiKey: 'pk_live_xxx',
27
+ mode: 'floating',
28
+ theme: 'auto',
29
+ position: 'bottom-right',
30
+ });
31
+ </script>
32
+ ```
33
+
34
+ ### npm
35
+
36
+ ```bash
37
+ npm install @thisispamela/widget
38
+ ```
39
+
40
+ ```javascript
41
+ import Pamela from '@thisispamela/widget';
42
+
43
+ Pamela.init({ apiKey: 'pk_live_xxx', mode: 'floating' });
44
+ ```
45
+
46
+ ## API
47
+
48
+ ### `Pamela.init(options)`
49
+
50
+ | Option | Type | Default | Description |
51
+ | ---------- | ------ | -------------- | ------------------------------ |
52
+ | `apiKey` | string | **required** | Enterprise API key |
53
+ | `mode` | string | `'floating'` | `'floating'` \| `'modal'` \| `'inline'` \| `'none'` |
54
+ | `theme` | string | `'auto'` | `'light'` \| `'dark'` \| `'auto'` |
55
+ | `position` | string | `'bottom-right'` | Floating button position |
56
+ | `baseUrl` | string | Production API | Custom API base URL |
57
+ | `defaults` | object | — | Default voice, agentName, callerName, maxDuration |
58
+ | `styles` | object | — | CSS variable overrides: `--pamela-accent`, `--pamela-primary`, `--pamela-background`, `--pamela-text`, `--pamela-border-radius`, `--pamela-font` |
59
+
60
+ ### `Pamela.call(options)`
61
+
62
+ Start a call programmatically.
63
+
64
+ ```javascript
65
+ const call = await Pamela.call({
66
+ to: '+15551234567',
67
+ task: 'Schedule a demo for tomorrow at 2pm',
68
+ voice: 'auto',
69
+ agentName: 'Pamela',
70
+ callerName: 'Acme Corp',
71
+ });
72
+ ```
73
+
74
+ ### `Pamela.getCall(callId)` / `Pamela.cancel(callId)`
75
+
76
+ Get call status or cancel an in-progress call.
77
+
78
+ ### `Pamela.on(event, callback)` / `Pamela.off(event, callback)`
79
+
80
+ Events: `call:start`, `call:update`, `call:complete`, `call:error`, `modal:open`, `modal:close`.
81
+
82
+ ### `Pamela.destroy()`
83
+
84
+ Remove the widget and clean up.
85
+
86
+ ## Inline mode
87
+
88
+ Add call buttons to existing elements:
89
+
90
+ ```html
91
+ <div
92
+ data-pamela-call
93
+ data-to="+15551234567"
94
+ data-task="Schedule a demo"
95
+ data-voice="auto"
96
+ data-label="Call with Pamela"
97
+ ></div>
98
+ ```
99
+
100
+ The widget discovers these on load and watches for dynamically added elements. When you click an inline button, the modal opens (if you use `mode: 'inline'`) and shows call status and transcript until the call completes.
101
+
102
+ ## Modal mode
103
+
104
+ Use the full modal UI (phone input, task textarea, voice select, status + transcript):
105
+
106
+ ```javascript
107
+ Pamela.init({ apiKey: 'pk_live_xxx', mode: 'modal' });
108
+ // Open the modal programmatically if you want:
109
+ Pamela.show();
110
+ ```
111
+
112
+ ## Theming
113
+
114
+ The widget uses CSS variables aligned with the Pamela design system (light and dark). Themes: **Light** (default), **Dark** (auto-detected via `prefers-color-scheme`, `.dark` class, or `data-pamela-theme="dark"`). Pass `theme: 'light'` or `theme: 'dark'` to force, or `theme: 'auto'` (default). Override at init with `styles: { '--pamela-primary': '#f97316', '--pamela-background': '#ffffff', '--pamela-text': '#1f2937', '--pamela-border-radius': '8px', '--pamela-font': '...' }` or override tokens in your CSS on `.pamela-widget-root`.
115
+
116
+ ## Distribution
117
+
118
+ - **Full bundle:** `dist/widget.js` (IIFE), `dist/widget.esm.js` (ESM), `dist/widget.d.ts` (types)
119
+ - **Minified:** `npm run build:min` produces `dist/widget.min.js` for production/CDN
120
+ - **npm:** `npm publish` (package `@thisispamela/widget`, `publishConfig.access: public`)
121
+ - **CDN URLs:** `https://cdn.thisispamela.com/widget.js` (primary), `https://unpkg.com/@thisispamela/widget`, `https://cdn.jsdelivr.net/npm/@thisispamela/widget`
122
+
123
+ ## Local demo
124
+
125
+ After `npm run build`, serve the package directory and open `demo.html` (e.g. `npx serve .` then visit `/demo.html`). Replace `apiKey` in the script with a valid key to test the floating button and call flow.
126
+
127
+ ## Security
128
+
129
+ API keys used in the widget are visible in the frontend. Use project/domain allowlists in the dashboard and prefer restricted public keys (`pk_*`) for widget use. See [WIDGET_ARCHITECTURE.md](../../docs/architecture/WIDGET_ARCHITECTURE.md#security-considerations).
130
+
131
+ ## Architecture
132
+
133
+ See [docs/architecture/WIDGET_ARCHITECTURE.md](../../docs/architecture/WIDGET_ARCHITECTURE.md) for bundle strategy, security, and implementation details.
package/dist/api.d.ts ADDED
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Lightweight fetch-based API client for the widget.
3
+ * Imports shared types from @thisispamela/sdk for alignment.
4
+ */
5
+ import type { PamelaCall, PamelaCallOptions } from './types';
6
+ export declare class PamelaError extends Error {
7
+ code?: string;
8
+ errorCode?: number;
9
+ statusCode?: number;
10
+ details?: Record<string, unknown>;
11
+ constructor(message: string, options?: {
12
+ code?: string;
13
+ errorCode?: number;
14
+ statusCode?: number;
15
+ details?: Record<string, unknown>;
16
+ });
17
+ }
18
+ export interface ApiClientOptions {
19
+ authToken: string;
20
+ baseUrl?: string;
21
+ }
22
+ export declare class PamelaApiClient {
23
+ private authToken;
24
+ private baseUrl;
25
+ constructor(options: ApiClientOptions);
26
+ private request;
27
+ createCall(options: PamelaCallOptions): Promise<PamelaCall>;
28
+ getCall(callId: string): Promise<PamelaCall>;
29
+ cancelCall(callId: string): Promise<void>;
30
+ /**
31
+ * Poll call status until terminal state or timeout.
32
+ */
33
+ pollCallStatus(callId: string, options?: {
34
+ intervalMs?: number;
35
+ timeoutMs?: number;
36
+ }): Promise<PamelaCall>;
37
+ }
38
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,UAAU,EACV,iBAAiB,EAIlB,MAAM,SAAS,CAAC;AAEjB,qBAAa,WAAY,SAAQ,KAAK;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAGhC,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QACR,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACnC;CASJ;AAgCD,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,EAAE,gBAAgB;YAKvB,OAAO;IAyCf,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC;IAkB3D,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAK5C,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/C;;OAEG;IACG,cAAc,CAClB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO,GACxD,OAAO,CAAC,UAAU,CAAC;CAgBvB"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Simple event emitter for widget callbacks
3
+ */
4
+ type Listener = (...args: unknown[]) => void;
5
+ export declare class EventEmitter {
6
+ private listeners;
7
+ on(event: string, callback: Listener): void;
8
+ off(event: string, callback: Listener): void;
9
+ emit(event: string, ...args: unknown[]): void;
10
+ removeAllListeners(event?: string): void;
11
+ }
12
+ export {};
13
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,KAAK,QAAQ,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;AAE7C,qBAAa,YAAY;IACvB,OAAO,CAAC,SAAS,CAAsC;IAEvD,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAM3C,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAQ5C,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAY7C,kBAAkB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;CAOzC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @thisispamela/widget - Embeddable Pamela Voice AI widget
3
+ *
4
+ * Usage (script tag):
5
+ * <script src="https://cdn.thisispamela.com/widget.js"></script>
6
+ * <script>
7
+ * Pamela.init({ apiKey: 'pk_live_xxx', mode: 'floating' });
8
+ * </script>
9
+ *
10
+ * Usage (ESM):
11
+ * import Pamela from '@thisispamela/widget';
12
+ * Pamela.init({ apiKey: 'pk_live_xxx' });
13
+ */
14
+ import { Pamela } from './pamela';
15
+ import { PamelaError } from './api';
16
+ import type { PamelaInitOptions, PamelaCallOptions, PamelaCall, PamelaStyleOverrides, TranscriptEntry } from './types';
17
+ export { Pamela, PamelaError };
18
+ export type { PamelaInitOptions, PamelaCallOptions, PamelaCall, PamelaStyleOverrides, TranscriptEntry };
19
+ export default Pamela;
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,UAAU,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAOvH,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;AAC/B,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,UAAU,EAAE,oBAAoB,EAAE,eAAe,EAAE,CAAC;AAExG,eAAe,MAAM,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Main Pamela widget class: init, call, events, UI modes
3
+ */
4
+ import type { PamelaInitOptions, PamelaCallOptions, PamelaCall } from './types';
5
+ export declare class Pamela {
6
+ private static instance;
7
+ private api;
8
+ private options;
9
+ private events;
10
+ private floatingButton;
11
+ private inlineButton;
12
+ private modal;
13
+ private container;
14
+ private theme;
15
+ static init(options: PamelaInitOptions): Pamela;
16
+ private init;
17
+ private handleCreateCall;
18
+ call(options: PamelaCallOptions): Promise<PamelaCall>;
19
+ getCall(callId: string): Promise<PamelaCall>;
20
+ cancel(callId: string): Promise<void>;
21
+ on(event: string, callback: (...args: unknown[]) => void): void;
22
+ off(event: string, callback: (...args: unknown[]) => void): void;
23
+ show(): void;
24
+ hide(): void;
25
+ destroy(): void;
26
+ static getInstance(): Pamela | null;
27
+ }
28
+ //# sourceMappingURL=pamela.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pamela.d.ts","sourceRoot":"","sources":["../src/pamela.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EACjB,UAAU,EACX,MAAM,SAAS,CAAC;AAejB,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAuB;IAE9C,OAAO,CAAC,GAAG,CAAgC;IAC3C,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,SAAS,CAA4B;IAC7C,OAAO,CAAC,KAAK,CAA6B;IAE1C,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM;IAU/C,OAAO,CAAC,IAAI;YA8DE,gBAAgB;IA0B9B,IAAI,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC;IAKrD,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAK5C,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKrC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI;IAI/D,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI;IAIhE,IAAI,IAAI,IAAI;IAKZ,IAAI,IAAI,IAAI;IAKZ,OAAO,IAAI,IAAI;IAef,MAAM,CAAC,WAAW,IAAI,MAAM,GAAG,IAAI;CAGpC"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Pamela Widget - TypeScript interfaces
3
+ */
4
+ import type { CallStatusValue } from '@thisispamela/sdk/types';
5
+ export interface PamelaInitOptions {
6
+ apiKey?: string;
7
+ accessToken?: string;
8
+ theme?: 'light' | 'dark' | 'auto';
9
+ position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
10
+ mode?: 'floating' | 'modal' | 'inline' | 'none';
11
+ baseUrl?: string;
12
+ defaults?: {
13
+ voice?: string;
14
+ agentName?: string;
15
+ callerName?: string;
16
+ maxDuration?: number;
17
+ };
18
+ styles?: Partial<PamelaStyleOverrides>;
19
+ }
20
+ export interface PamelaCallOptions {
21
+ to: string;
22
+ task: string;
23
+ voice?: string;
24
+ agentName?: string;
25
+ callerName?: string;
26
+ maxDuration?: number;
27
+ metadata?: Record<string, string>;
28
+ webhooks?: {
29
+ onComplete?: string;
30
+ onFailed?: string;
31
+ };
32
+ }
33
+ export interface TranscriptEntry {
34
+ role: 'agent' | 'recipient';
35
+ content: string;
36
+ timestamp: number;
37
+ }
38
+ export interface PamelaCall {
39
+ id: string;
40
+ status: CallStatusValue;
41
+ to: string;
42
+ task: string;
43
+ duration?: number;
44
+ transcript?: TranscriptEntry[];
45
+ summary?: string;
46
+ createdAt: string;
47
+ completedAt?: string;
48
+ }
49
+ export interface PamelaStyleOverrides {
50
+ '--pamela-accent'?: string;
51
+ '--pamela-accent-2'?: string;
52
+ '--pamela-primary'?: string;
53
+ '--pamela-background'?: string;
54
+ '--pamela-text'?: string;
55
+ '--pamela-radius'?: string;
56
+ '--pamela-border-radius'?: string;
57
+ '--pamela-font'?: string;
58
+ }
59
+ /** Raw API response (snake_case) from backend */
60
+ export interface ApiCallResponse {
61
+ id: string;
62
+ status: string;
63
+ call_session_id: string;
64
+ created_at: string;
65
+ }
66
+ export interface ApiCallStatusResponse {
67
+ id: string;
68
+ status: string;
69
+ to: string;
70
+ from_: string;
71
+ country: string;
72
+ created_at: string;
73
+ started_at?: string;
74
+ completed_at?: string;
75
+ duration_seconds?: number;
76
+ max_duration_seconds?: number;
77
+ transcript?: Array<{
78
+ role: string;
79
+ content: string;
80
+ timestamp?: number;
81
+ }>;
82
+ summary?: string;
83
+ metadata: Record<string, unknown>;
84
+ }
85
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Floating call button that expands to a mini form (phone + task + Call Now)
3
+ */
4
+ import type { PamelaCall } from '../types';
5
+ export interface FloatingButtonOptions {
6
+ position: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
7
+ theme: 'light' | 'dark';
8
+ defaults?: {
9
+ voice?: string;
10
+ agentName?: string;
11
+ callerName?: string;
12
+ };
13
+ onCreateCall: (to: string, task: string) => void;
14
+ onExpand?: () => void;
15
+ onCollapse?: () => void;
16
+ }
17
+ export declare class FloatingButton {
18
+ private options;
19
+ private root;
20
+ private wrapper;
21
+ private panel;
22
+ private expanded;
23
+ private currentCall;
24
+ constructor(options: FloatingButtonOptions);
25
+ render(container: HTMLElement): HTMLElement;
26
+ private getWrapperStyles;
27
+ private getButtonStyles;
28
+ private toggle;
29
+ private handleSubmit;
30
+ setCallStatus(call: PamelaCall | null): void;
31
+ destroy(): void;
32
+ }
33
+ //# sourceMappingURL=FloatingButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FloatingButton.d.ts","sourceRoot":"","sources":["../../src/ui/FloatingButton.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAW3C,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,cAAc,GAAG,aAAa,GAAG,WAAW,GAAG,UAAU,CAAC;IACpE,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACvE,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,IAAI,CAA4B;IACxC,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,KAAK,CAA4B;IACzC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,WAAW,CAA2B;gBAElC,OAAO,EAAE,qBAAqB;IAI1C,MAAM,CAAC,SAAS,EAAE,WAAW,GAAG,WAAW;IA8E3C,OAAO,CAAC,gBAAgB;IAUxB,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,MAAM;IASd,OAAO,CAAC,YAAY;IAmBpB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI;IAkB5C,OAAO,IAAI,IAAI;CAMhB"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Inline button mode: attach call buttons to elements with data-pamela-call
3
+ * Auto-initializes on DOM ready and watches for dynamically added elements.
4
+ */
5
+ export interface InlineButtonOptions {
6
+ theme: 'light' | 'dark';
7
+ onCallClick: (params: {
8
+ to: string;
9
+ task: string;
10
+ voice?: string;
11
+ }) => void;
12
+ }
13
+ export declare class InlineButton {
14
+ private options;
15
+ private observer;
16
+ private styleInjected;
17
+ constructor(options: InlineButtonOptions);
18
+ /**
19
+ * Scan the document for [data-pamela-call] and attach buttons.
20
+ */
21
+ attach(root?: Document | HTMLElement): void;
22
+ private attachToElement;
23
+ /**
24
+ * Start watching for dynamically added [data-pamela-call] elements.
25
+ */
26
+ observe(root?: Document | HTMLElement): void;
27
+ destroy(): void;
28
+ }
29
+ //# sourceMappingURL=InlineButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InlineButton.d.ts","sourceRoot":"","sources":["../../src/ui/InlineButton.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC;IACxB,WAAW,EAAE,CAAC,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CAC7E;AAyBD,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,aAAa,CAAS;gBAElB,OAAO,EAAE,mBAAmB;IAIxC;;OAEG;IACH,MAAM,CAAC,IAAI,GAAE,QAAQ,GAAG,WAAsB,GAAG,IAAI;IAWrD,OAAO,CAAC,eAAe;IA8BvB;;OAEG;IACH,OAAO,CAAC,IAAI,GAAE,QAAQ,GAAG,WAAsB,GAAG,IAAI;IAqBtD,OAAO,IAAI,IAAI;CAIhB"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Full-featured call modal with status + transcript display.
3
+ */
4
+ import type { PamelaCall } from '../types';
5
+ export interface ModalOptions {
6
+ theme: 'light' | 'dark';
7
+ defaults?: {
8
+ voice?: string;
9
+ agentName?: string;
10
+ callerName?: string;
11
+ };
12
+ onCreateCall: (to: string, task: string, voice?: string) => void;
13
+ onClose?: () => void;
14
+ }
15
+ export declare class Modal {
16
+ private options;
17
+ private root;
18
+ private overlay;
19
+ private panel;
20
+ private orbEl;
21
+ private statusEl;
22
+ private transcriptEl;
23
+ private summaryEl;
24
+ private expanded;
25
+ private boundKeydown;
26
+ constructor(options: ModalOptions);
27
+ render(container: HTMLElement): HTMLElement;
28
+ open(): void;
29
+ close(): void;
30
+ setCallStatus(call: PamelaCall | null): void;
31
+ destroy(): void;
32
+ private renderTranscriptEntry;
33
+ private handleSubmit;
34
+ private getOverlayStyles;
35
+ private getSelectStyles;
36
+ private getCloseStyles;
37
+ private getTranscriptWrapperStyles;
38
+ private getTranscriptStyles;
39
+ private getTranscriptBubbleStyles;
40
+ private getOrbStyles;
41
+ }
42
+ //# sourceMappingURL=Modal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Modal.d.ts","sourceRoot":"","sources":["../../src/ui/Modal.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAmB,MAAM,UAAU,CAAC;AAM5D,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACvE,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACjE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,qBAAa,KAAK;IAChB,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,IAAI,CAA4B;IACxC,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,KAAK,CAA4B;IACzC,OAAO,CAAC,KAAK,CAA4B;IACzC,OAAO,CAAC,QAAQ,CAA4B;IAC5C,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,SAAS,CAA4B;IAC7C,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,YAAY,CAA6C;gBAErD,OAAO,EAAE,YAAY;IAIjC,MAAM,CAAC,SAAS,EAAE,WAAW,GAAG,WAAW;IAoI3C,IAAI,IAAI,IAAI;IAMZ,KAAK,IAAI,IAAI;IAOb,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI;IAqC5C,OAAO,IAAI,IAAI;IAef,OAAO,CAAC,qBAAqB;IAO7B,OAAO,CAAC,YAAY;IAqBpB,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,0BAA0B;IAOlC,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,yBAAyB;IAWjC,OAAO,CAAC,YAAY;CAQrB"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Inline SVG icons for the widget (no external assets)
3
+ */
4
+ export declare const ICON_LOGO = "<svg viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><circle cx=\"16\" cy=\"16\" r=\"14\" fill=\"url(#pamela-g)\" stroke=\"rgba(255,255,255,0.4)\" stroke-width=\"1.5\"/><path d=\"M12 11v10l8-5-8-5z\" fill=\"white\"/><defs><linearGradient id=\"pamela-g\" x1=\"8\" y1=\"8\" x2=\"24\" y2=\"24\" gradientUnits=\"userSpaceOnUse\"><stop stop-color=\"#F27A1A\"/><stop offset=\"1\" stop-color=\"#F06C4F\"/></linearGradient></defs></svg>";
5
+ export declare const ICON_PHONE = "<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07 19.5 19.5 0 01-6-6 19.79 19.79 0 01-3.07-8.67A2 2 0 014.11 2h3a2 2 0 012 1.72 12.84 12.84 0 00.7 2.81 2 2 0 01-.45 2.11L8.09 9.91a16 16 0 006 6l1.27-1.27a2 2 0 012.11-.45 12.84 12.84 0 002.81.7A2 2 0 0122 16.92z\"/></svg>";
6
+ export declare const ICON_CLOSE = "<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>";
7
+ export declare const ICON_CALL = "<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07 19.5 19.5 0 01-6-6 19.79 19.79 0 01-3.07-8.67A2 2 0 014.11 2h3a2 2 0 012 1.72 12.84 12.84 0 00.7 2.81 2 2 0 01-.45 2.11L8.09 9.91a16 16 0 006 6l1.27-1.27a2 2 0 012.11-.45 12.84 12.84 0 002.81.7A2 2 0 0122 16.92z\"/></svg>";
8
+ //# sourceMappingURL=icons.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../../src/ui/icons.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,SAAS,0cAC2Y,CAAC;AAEla,eAAO,MAAM,UAAU,0aACoY,CAAC;AAE5Z,eAAO,MAAM,UAAU,4OACwL,CAAC;AAEhN,eAAO,MAAM,SAAS,0aACqY,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Design tokens aligned with WEBSITE_DESIGN_SCHEMA.md (light + dark).
3
+ * Plan aliases: --pamela-primary, --pamela-background, --pamela-border-radius for host overrides.
4
+ */
5
+ export declare function injectStyles(theme: 'light' | 'dark'): void;
6
+ export declare function getThemeClass(theme: 'light' | 'dark'): string;
7
+ /** Style overrides from PamelaStyleOverrides (init options.styles) */
8
+ export type StyleOverrides = import('../types').PamelaStyleOverrides;
9
+ /**
10
+ * Apply custom CSS variable overrides to widget roots.
11
+ * Call after injectStyles; host can pass options.styles from init.
12
+ */
13
+ export declare function applyStyleOverrides(overrides: Partial<StyleOverrides>): void;
14
+ //# sourceMappingURL=styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/ui/styles.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAkFH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAQ1D;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAE7D;AAED,sEAAsE;AACtE,MAAM,MAAM,cAAc,GAAG,OAAO,UAAU,EAAE,oBAAoB,CAAC;AAErE;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI,CAuB5E"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Phone helpers for the widget (lightweight, no external deps).
3
+ */
4
+ export declare function normalizePhone(value: string): string;
5
+ export declare function isValidE164(value: string): boolean;
6
+ //# sourceMappingURL=phone.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phone.d.ts","sourceRoot":"","sources":["../../src/utils/phone.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOpD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAElD"}
@@ -0,0 +1,20 @@
1
+ type PanelStyleOptions = {
2
+ width?: string;
3
+ minWidth?: string;
4
+ maxWidth?: string;
5
+ padding?: string;
6
+ borderRadiusVar?: string;
7
+ gap?: string;
8
+ };
9
+ type InputStyleOptions = {
10
+ padding?: string;
11
+ fontSize?: string;
12
+ };
13
+ type CtaStyleOptions = {
14
+ padding?: string;
15
+ };
16
+ export declare function buildPanelStyles(options?: PanelStyleOptions): string;
17
+ export declare function buildInputStyles(options?: InputStyleOptions): string;
18
+ export declare function buildCtaStyles(options?: CtaStyleOptions): string;
19
+ export {};
20
+ //# sourceMappingURL=styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/utils/styles.ts"],"names":[],"mappings":"AAAA,KAAK,iBAAiB,GAAG;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,KAAK,iBAAiB,GAAG;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,iBAAsB,GAAG,MAAM,CAsBxE;AAED,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,iBAAsB,GAAG,MAAM,CAQxE;AAED,wBAAgB,cAAc,CAAC,OAAO,GAAE,eAAoB,GAAG,MAAM,CAOpE"}
@@ -0,0 +1,123 @@
1
+ import { CallStatusValue } from '@thisispamela/sdk/types';
2
+
3
+ /**
4
+ * Pamela Widget - TypeScript interfaces
5
+ */
6
+
7
+ interface PamelaInitOptions {
8
+ apiKey?: string;
9
+ accessToken?: string;
10
+ theme?: 'light' | 'dark' | 'auto';
11
+ position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
12
+ mode?: 'floating' | 'modal' | 'inline' | 'none';
13
+ baseUrl?: string;
14
+ defaults?: {
15
+ voice?: string;
16
+ agentName?: string;
17
+ callerName?: string;
18
+ maxDuration?: number;
19
+ };
20
+ styles?: Partial<PamelaStyleOverrides>;
21
+ }
22
+ interface PamelaCallOptions {
23
+ to: string;
24
+ task: string;
25
+ voice?: string;
26
+ agentName?: string;
27
+ callerName?: string;
28
+ maxDuration?: number;
29
+ metadata?: Record<string, string>;
30
+ webhooks?: {
31
+ onComplete?: string;
32
+ onFailed?: string;
33
+ };
34
+ }
35
+ interface TranscriptEntry {
36
+ role: 'agent' | 'recipient';
37
+ content: string;
38
+ timestamp: number;
39
+ }
40
+ interface PamelaCall {
41
+ id: string;
42
+ status: CallStatusValue;
43
+ to: string;
44
+ task: string;
45
+ duration?: number;
46
+ transcript?: TranscriptEntry[];
47
+ summary?: string;
48
+ createdAt: string;
49
+ completedAt?: string;
50
+ }
51
+ interface PamelaStyleOverrides {
52
+ '--pamela-accent'?: string;
53
+ '--pamela-accent-2'?: string;
54
+ '--pamela-primary'?: string;
55
+ '--pamela-background'?: string;
56
+ '--pamela-text'?: string;
57
+ '--pamela-radius'?: string;
58
+ '--pamela-border-radius'?: string;
59
+ '--pamela-font'?: string;
60
+ }
61
+
62
+ /**
63
+ * Main Pamela widget class: init, call, events, UI modes
64
+ */
65
+
66
+ declare class Pamela {
67
+ private static instance;
68
+ private api;
69
+ private options;
70
+ private events;
71
+ private floatingButton;
72
+ private inlineButton;
73
+ private modal;
74
+ private container;
75
+ private theme;
76
+ static init(options: PamelaInitOptions): Pamela;
77
+ private init;
78
+ private handleCreateCall;
79
+ call(options: PamelaCallOptions): Promise<PamelaCall>;
80
+ getCall(callId: string): Promise<PamelaCall>;
81
+ cancel(callId: string): Promise<void>;
82
+ on(event: string, callback: (...args: unknown[]) => void): void;
83
+ off(event: string, callback: (...args: unknown[]) => void): void;
84
+ show(): void;
85
+ hide(): void;
86
+ destroy(): void;
87
+ static getInstance(): Pamela | null;
88
+ }
89
+
90
+ /**
91
+ * Lightweight fetch-based API client for the widget.
92
+ * Imports shared types from @thisispamela/sdk for alignment.
93
+ */
94
+
95
+ declare class PamelaError extends Error {
96
+ code?: string;
97
+ errorCode?: number;
98
+ statusCode?: number;
99
+ details?: Record<string, unknown>;
100
+ constructor(message: string, options?: {
101
+ code?: string;
102
+ errorCode?: number;
103
+ statusCode?: number;
104
+ details?: Record<string, unknown>;
105
+ });
106
+ }
107
+
108
+ /**
109
+ * @thisispamela/widget - Embeddable Pamela Voice AI widget
110
+ *
111
+ * Usage (script tag):
112
+ * <script src="https://cdn.thisispamela.com/widget.js"></script>
113
+ * <script>
114
+ * Pamela.init({ apiKey: 'pk_live_xxx', mode: 'floating' });
115
+ * </script>
116
+ *
117
+ * Usage (ESM):
118
+ * import Pamela from '@thisispamela/widget';
119
+ * Pamela.init({ apiKey: 'pk_live_xxx' });
120
+ */
121
+
122
+ export { Pamela, PamelaError, Pamela as default };
123
+ export type { PamelaCall, PamelaCallOptions, PamelaInitOptions, PamelaStyleOverrides, TranscriptEntry };