@askly/widget 2.4.0 → 2.6.1

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 CHANGED
@@ -89,7 +89,7 @@ Askly.identify({
89
89
  | :--- | :--- | :--- |
90
90
  | `userId` | `string` | **Required.** Your application's user ID. |
91
91
  | `hash` | `string` | HMAC-SHA256 of `userId + timestamp`, using your Widget Secret Key. |
92
- | `timestamp` | `number` | Unix seconds the hash was generated for. Valid for 5 minutes. |
92
+ | `timestamp` | `number` | **Required with `hash`.** Unix seconds the hash was generated for. Valid for 5 minutes. |
93
93
  | `email` / `name` / `phone` | `string` | Optional profile fields shown to your agents. |
94
94
  | `attributes` | `object` | Any extra traits you want on the contact record. |
95
95
 
@@ -108,6 +108,11 @@ const hash = crypto
108
108
 
109
109
  Without a valid `hash` the traits are still used locally, but Askly will not link the accounts.
110
110
 
111
+ > **Known limitation:** a signature is accepted for 5 minutes from its `timestamp`. On a page that
112
+ > stays open longer, call `Askly.identify()` again with a freshly generated `hash` and `timestamp`
113
+ > (for example on a timer, or before the user opens the chat). If `identify()` is rejected, the
114
+ > reason is logged to the browser console.
115
+
111
116
  #### Logging out
112
117
 
113
118
  ```javascript
@@ -116,7 +121,13 @@ Askly.shutdown(); // the same, and remove the widget from the page
116
121
  ```
117
122
 
118
123
  Call one of these on logout, particularly for shared computers — otherwise the next person to
119
- use the browser inherits the previous person's conversations.
124
+ use the browser inherits the previous person's conversations. `reset()` takes effect immediately
125
+ in an open widget: the transcript on screen is cleared, a new anonymous visitor id is issued, and
126
+ any identity passed to `init()` stops being sent. After `shutdown()` you can call `init()` again.
127
+
128
+ Both really do discard the anonymous visitor: the next message comes from a new visitor with no
129
+ history. Call them on logout only — not on every page load for guests, and not to hide the widget
130
+ on some routes (use `includePaths` / `excludePaths`, or `Askly.close()`, for that).
120
131
 
121
132
  #### Identifying at init time
122
133
 
@@ -196,6 +207,20 @@ Askly.init({
196
207
 
197
208
  None required. The widget talks to Askly's hosted backend automatically — you only provide an `appId`.
198
209
 
210
+ ### Reply formatting
211
+
212
+ The server and the widget share one rendering contract, the **Askly reply markdown subset v1**. The AI is instructed to write only this subset, the server normalises anything else away, and the widget renders exactly this subset with a small built-in parser (no third-party markdown library). Every message carries a `format` field: `"markdown"` for AI replies, `"text"` for operator replies and visitor messages, which are shown verbatim with URLs auto-linked.
213
+
214
+ | Allowed | Syntax |
215
+ | --- | --- |
216
+ | Paragraphs | blank line between them; a single newline is a soft break |
217
+ | Bold, italic | `**bold**`, `*italic*` or `_italic_` |
218
+ | Inline code, code blocks | `` `code` ``, fenced ```` ``` ```` with an optional language |
219
+ | Lists | `- item`, `* item`, `1. item`; never nested |
220
+ | Links | `[text](https://…)` (https, http, mailto, tel) and bare URLs |
221
+
222
+ Headings, tables, images, blockquotes, horizontal rules and raw HTML are not part of the contract and appear as literal text. The canonical definition lives in `src/markdown.ts`; the server copy is `app/services/reply_format.py`.
223
+
199
224
  ## Development
200
225
 
201
226
  ```bash
package/dist/icons.d.ts CHANGED
@@ -9,6 +9,8 @@ export declare const Minus: ({ size, color, strokeWidth, ...rest }: IconProps) =
9
9
  export declare const ArrowUp: ({ size, color, strokeWidth, ...rest }: IconProps) => React.ReactSVGElement;
10
10
  export declare const Mic: ({ size, color, strokeWidth, ...rest }: IconProps) => React.ReactSVGElement;
11
11
  export declare const MicOff: ({ size, color, strokeWidth, ...rest }: IconProps) => React.ReactSVGElement;
12
+ export declare const Volume2: ({ size, color, strokeWidth, ...rest }: IconProps) => React.ReactSVGElement;
13
+ export declare const VolumeX: ({ size, color, strokeWidth, ...rest }: IconProps) => React.ReactSVGElement;
12
14
  export declare const Home: ({ size, color, strokeWidth, ...rest }: IconProps) => React.ReactSVGElement;
13
15
  export declare const Compass: ({ size, color, strokeWidth, ...rest }: IconProps) => React.ReactSVGElement;
14
16
  export declare const MessageSquare: ({ size, color, strokeWidth, ...rest }: IconProps) => React.ReactSVGElement;
@@ -17,12 +17,17 @@
17
17
  * The stable per-browser token for this organization, minting one if needed.
18
18
  * Scoped per org so a browser visiting two Askly-powered sites keeps them separate.
19
19
  */
20
- export declare function getVisitorId(orgId: string): string;
20
+ export declare function getVisitorId(orgId: string, adoptFrom?: string): string;
21
21
  /**
22
22
  * Forget this browser's identity and chat history — call on logout so the next person at
23
23
  * a shared computer starts clean rather than inheriting the previous session.
24
24
  */
25
25
  export declare function resetVisitor(orgId: string): void;
26
+ /**
27
+ * Record that data initialised under `scope` (the app id, or "detect") actually lives under
28
+ * `resolved` (the organization id from remote config). Not personal data, so reset keeps it.
29
+ */
30
+ export declare function rememberResolvedScope(scope: string, resolved: string): void;
26
31
  /** A fresh server-side thread id. Mirrors the local chat id so one chat is one thread. */
27
32
  export declare function newThreadKey(): string;
28
33
  export interface AsklyIdentity {
@@ -30,7 +35,10 @@ export interface AsklyIdentity {
30
35
  userId: string;
31
36
  /** HMAC-SHA256 of `userId + timestamp` under the org's widget secret, computed server-side. */
32
37
  hash?: string;
33
- /** Unix seconds the hash was generated for. Defaults to now. */
38
+ /**
39
+ * Unix seconds the hash was generated for. Required with `hash`: the server recomputes the
40
+ * HMAC from this exact value and rejects it once it is more than 5 minutes old.
41
+ */
34
42
  timestamp?: number;
35
43
  email?: string;
36
44
  name?: string;
@@ -47,4 +55,10 @@ type IdentityListener = (identity: AsklyIdentity) => void;
47
55
  export declare function publishIdentity(identity: AsklyIdentity): void;
48
56
  export declare function subscribeIdentity(listener: IdentityListener): () => void;
49
57
  export declare function clearIdentity(): void;
58
+ type ResetListener = () => void;
59
+ /** How many times reset() has run on this page. Lets a widget notice a reset it missed. */
60
+ export declare function getResetGeneration(): number;
61
+ /** Tell the mounted widget that Askly.reset() ran, so it drops what it holds in memory. */
62
+ export declare function publishReset(): void;
63
+ export declare function subscribeReset(listener: ResetListener): () => void;
50
64
  export {};
package/dist/index.d.ts CHANGED
@@ -9,6 +9,7 @@ export interface AsklyConfig {
9
9
  themeColor?: string;
10
10
  theme?: "light" | "dark" | "auto";
11
11
  enableVoiceChat?: boolean;
12
+ readAloud?: boolean;
12
13
  welcomeMessage?: string;
13
14
  placeholderText?: string;
14
15
  organizationLogo?: string;
@@ -26,6 +27,7 @@ export interface AsklyConfig {
26
27
  excludePaths?: string[];
27
28
  includePaths?: string[];
28
29
  configOverride?: Record<string, any>;
30
+ debug?: boolean;
29
31
  onMessageSent?: (message: string) => void;
30
32
  onMessageReceived?: (reply: string) => void;
31
33
  onChatOpened?: () => void;