@kavchat/widget 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -4
- package/dist/index.mjs +892 -117
- package/dist/kavchat-live.js +20 -0
- package/dist/kavchat.js +4 -4
- package/dist/types/live-client.d.ts +85 -0
- package/dist/types/live-entry.d.ts +1 -0
- package/dist/types/live-load-cdn.d.ts +2 -0
- package/dist/types/live-load.d.ts +5 -0
- package/dist/types/live-styles.d.ts +5 -0
- package/dist/types/live.d.ts +67 -0
- package/dist/types/widget.d.ts +13 -0
- package/package.json +2 -2
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { LiveChat, LiveConversation } from '@kavchat/core';
|
|
2
|
+
/**
|
|
3
|
+
* הרשת של צ'אט עם נציג (docs/live-chat-protocol.md, סעיפים 2 ו-3).
|
|
4
|
+
* בלי preflight: אין כותרות בכלל, וגוף ה-POST הוא מחרוזת JSON, שהדפדפן שולח כ-text/plain.
|
|
5
|
+
* הקרדנשל עובר רק בגוף הבקשה. בכתובת יש רק כרטיס הזרם החד-פעמי
|
|
6
|
+
*/
|
|
7
|
+
export interface LiveApi {
|
|
8
|
+
apiBase: string;
|
|
9
|
+
publicKey: string;
|
|
10
|
+
}
|
|
11
|
+
export interface LiveRes {
|
|
12
|
+
status: number;
|
|
13
|
+
ok: boolean;
|
|
14
|
+
data: any;
|
|
15
|
+
code: string;
|
|
16
|
+
message: string;
|
|
17
|
+
}
|
|
18
|
+
export declare const liveUrl: (c: LiveApi, path: string) => string;
|
|
19
|
+
export declare const livePost: (c: LiveApi, path: string, body: unknown) => Promise<LiveRes>;
|
|
20
|
+
export declare const liveGet: (c: LiveApi, path: string) => Promise<LiveRes>;
|
|
21
|
+
/** רשת, 429 ו-5xx: מנסים שוב. 4xx אחר: לא */
|
|
22
|
+
export declare const retryable: (r: LiveRes) => boolean;
|
|
23
|
+
export declare const sleep: (ms: number) => Promise<unknown>;
|
|
24
|
+
/** בלי שום אירוע 90 שניות: סוגרים ומתחברים מחדש. EventSource לא חושף את שורות ה-ping, ולכן זמן נדיב מה-60 שבפרוטוקול */
|
|
25
|
+
export declare const LIVE_IDLE_MS = 90000;
|
|
26
|
+
export interface LiveCallbacks {
|
|
27
|
+
change(chat: LiveChat): void;
|
|
28
|
+
typing(on: boolean): void;
|
|
29
|
+
/** reconnecting: החיבור נפל ומנסים שוב. replaced: לשונית או מכשיר אחר לקחו את השיחה */
|
|
30
|
+
notice(kind: 'reconnecting' | 'replaced' | null): void;
|
|
31
|
+
/** השיחה הסתיימה (או שהקרדנשל כבר לא תקף): מוחקים אותו מהאחסון */
|
|
32
|
+
ended(): void;
|
|
33
|
+
}
|
|
34
|
+
export declare class LiveConnection {
|
|
35
|
+
private api;
|
|
36
|
+
credential: string;
|
|
37
|
+
private cb;
|
|
38
|
+
chat: LiveChat;
|
|
39
|
+
stopped: boolean;
|
|
40
|
+
random: () => number;
|
|
41
|
+
private es;
|
|
42
|
+
private timer;
|
|
43
|
+
private idle;
|
|
44
|
+
private typingTimer;
|
|
45
|
+
private attempt;
|
|
46
|
+
/** כישלונות זרם לפני ready, כשכרטיס הזרם התקבל: כנראה פרוקסי שחוסם SSE */
|
|
47
|
+
private blocked;
|
|
48
|
+
private pollUntil;
|
|
49
|
+
private polling;
|
|
50
|
+
private typingOn;
|
|
51
|
+
private typingAt;
|
|
52
|
+
private numberTried;
|
|
53
|
+
constructor(api: LiveApi, credential: string, conversation: LiveConversation, cb: LiveCallbacks);
|
|
54
|
+
get final(): boolean;
|
|
55
|
+
private body;
|
|
56
|
+
private set;
|
|
57
|
+
/** POST /live/sync עד hasMore=false. false: נכשל */
|
|
58
|
+
sync(): Promise<boolean>;
|
|
59
|
+
/** קודים שמשנים את הזרימה (סעיף 2.5). true: טופל */
|
|
60
|
+
private fail;
|
|
61
|
+
connect(): void;
|
|
62
|
+
private openStream;
|
|
63
|
+
private touch;
|
|
64
|
+
private closeStream;
|
|
65
|
+
private bye;
|
|
66
|
+
private retry;
|
|
67
|
+
/** אחרי השהיה: סנכרון לפי lastSeq, ואז זרם חדש */
|
|
68
|
+
private schedule;
|
|
69
|
+
private onOnline;
|
|
70
|
+
/** long-poll כשאין EventSource, כשהזרם חסום, או לזמן מה אחרי live_busy */
|
|
71
|
+
private poll;
|
|
72
|
+
private showTyping;
|
|
73
|
+
/** שליחת הודעה: מוצגת מיד כ"נשלח", עם clientId שנוצר פעם אחת ומשמש לכל ניסיון חוזר */
|
|
74
|
+
send(raw: string): 'ok' | 'empty' | 'too_long' | 'closed';
|
|
75
|
+
retrySend(clientId: string): void;
|
|
76
|
+
private deliver;
|
|
77
|
+
/** "מקליד" לנציג: לכל היותר פעם ב-3 שניות, false כשהשדה התרוקן או נשלח. בלי ניסיונות חוזרים */
|
|
78
|
+
typing(on: boolean): void;
|
|
79
|
+
/** "להשאיר הודעה במקום" או "סיום השיחה". בטוח לחזור עליהן */
|
|
80
|
+
command(path: 'leave-message' | 'end'): Promise<boolean>;
|
|
81
|
+
/** מצב סופי: סוגרים את הזרם ומוחקים את הקרדנשל. אם מספר הפנייה עוד לא ידוע, סנכרון אחד אחרי 2 שניות */
|
|
82
|
+
private finish;
|
|
83
|
+
private end;
|
|
84
|
+
stop(): void;
|
|
85
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* עיצוב מסך הצ'אט עם נציג. נוסף ל-Shadow DOM רק כשהקובץ הנפרד נטען.
|
|
3
|
+
* תכונות לוגיות בלבד, כמו בשאר הווידג'ט, כדי ש-RTL יהפוך הכל לבד
|
|
4
|
+
*/
|
|
5
|
+
export declare const LIVE_CSS = "\n.lstatus{flex:none;padding:8px 14px;font-size:13px;line-height:1.6;color:#374151;background:#fff;border-block-end:1px solid #e3e6ea}\n.lsys{align-self:center;max-width:90%;text-align:center;font-size:12px;color:#6b7280;padding:2px 8px}\n.lsep{margin-block:6px;border-block-start:1px solid #e3e6ea;padding-block-start:8px;align-self:stretch;max-width:none}\n.lname{display:block;font-size:11px;font-weight:600;color:#6b7280}\n.lp-sending{opacity:.65}\n.lp-failed{opacity:.85;outline:1px solid #b42318}\n.lp-failed .btn{display:block;margin-block-start:6px;padding:3px 8px;font-size:12px;color:#b42318;background:#fff;border-color:#b42318}\n.ltyping{flex:none;padding:0 14px 4px;font-size:12px;color:#6b7280}\n.lerror{flex:none;padding:0 14px}\n.lerror:empty{display:none}\n.lactions{flex:none;display:flex;flex-wrap:wrap;gap:6px;padding:4px 14px 8px}\n.lactions:empty{display:none}\n.lactions .btn{padding:6px 12px;font-size:14px}\n.note{margin:0;font-size:14px;color:#4b5563}\n.composer input:disabled{opacity:.5}\n.send:disabled{opacity:.5;cursor:default}\n.launcher.kc-unread::after{content:\"\";position:absolute;inset-block-start:4px;inset-inline-end:4px;width:12px;height:12px;border-radius:50%;background:#e11d48;border:2px solid #fff}\n";
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { BotChip, BotEffect, UiTexts } from '@kavchat/core';
|
|
2
|
+
import { LiveApi } from './live-client';
|
|
3
|
+
/**
|
|
4
|
+
* צד המבקר בצ'אט עם נציג, בתוך חלון הווידג'ט: הכפתור "שיחה עם נציג", טופס הבקשה, מסך ההמתנה, השיחה עצמה,
|
|
5
|
+
* ושחזור אחרי טעינה מחדש. נטען רק כש-liveChat.enabled (או כשיש שיחה פתוחה שמורה), כקובץ נפרד ב-CDN,
|
|
6
|
+
* כדי שהקובץ הראשי יישאר בתקציב. המנוע (סדר, כפילויות, טקסטים) ב-@kavchat/core
|
|
7
|
+
*/
|
|
8
|
+
export type LiveEffect = Extract<BotEffect, {
|
|
9
|
+
type: 'contact' | 'live';
|
|
10
|
+
}>;
|
|
11
|
+
export interface FormPrefill {
|
|
12
|
+
note?: string;
|
|
13
|
+
name?: string;
|
|
14
|
+
email?: string;
|
|
15
|
+
phone?: string;
|
|
16
|
+
message?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* מה שהבקר צריך מהווידג'ט. KavchatWidget עצמו מועבר לכאן: השמות כאן הם השדות והמתודות (הפרטיים) שלו
|
|
20
|
+
*/
|
|
21
|
+
export interface LiveHost {
|
|
22
|
+
api: LiveApi;
|
|
23
|
+
/** liveChat.enabled false: הקובץ נטען רק כדי לשחזר שיחה פתוחה, בלי להציע שיחה חדשה */
|
|
24
|
+
release: {
|
|
25
|
+
liveChat?: {
|
|
26
|
+
enabled: boolean;
|
|
27
|
+
};
|
|
28
|
+
} | null;
|
|
29
|
+
locale: string;
|
|
30
|
+
t: UiTexts;
|
|
31
|
+
ui: {
|
|
32
|
+
root: ShadowRoot;
|
|
33
|
+
panel: HTMLElement;
|
|
34
|
+
chatView: HTMLElement;
|
|
35
|
+
formView: HTMLElement;
|
|
36
|
+
live: HTMLElement;
|
|
37
|
+
launcher: HTMLElement;
|
|
38
|
+
} | null;
|
|
39
|
+
opts: {
|
|
40
|
+
userToken?: string;
|
|
41
|
+
userName?: string;
|
|
42
|
+
};
|
|
43
|
+
session: {
|
|
44
|
+
id: string;
|
|
45
|
+
} | null;
|
|
46
|
+
isOpen: boolean;
|
|
47
|
+
renderChips(): void;
|
|
48
|
+
showChat(): void;
|
|
49
|
+
showForm(effect: LiveEffect, pre: FormPrefill): void;
|
|
50
|
+
emit(event: {
|
|
51
|
+
type: 'live';
|
|
52
|
+
state: string;
|
|
53
|
+
id: string;
|
|
54
|
+
}): void;
|
|
55
|
+
}
|
|
56
|
+
export interface LiveController {
|
|
57
|
+
/** הכפתורים עם "שיחה עם נציג" לפני "פנייה לצוות", רק כשיש נציג זמין */
|
|
58
|
+
chips(chips: BotChip[]): BotChip[];
|
|
59
|
+
/** למה אין נציג, לשורה שמעל טופס הפנייה ('' בלי הסבר) */
|
|
60
|
+
note(): string;
|
|
61
|
+
start(effect: LiveEffect): Promise<void>;
|
|
62
|
+
restore(): Promise<void>;
|
|
63
|
+
/** true כשמסך הצ'אט עם הנציג מוצג והפוקוס עבר אליו */
|
|
64
|
+
focus(): boolean;
|
|
65
|
+
destroy(): void;
|
|
66
|
+
}
|
|
67
|
+
export declare function createLive(host: LiveHost): LiveController;
|
package/dist/types/widget.d.ts
CHANGED
|
@@ -23,6 +23,12 @@ export type KavchatEvent = {
|
|
|
23
23
|
type: 'ticket';
|
|
24
24
|
id: string;
|
|
25
25
|
number: number;
|
|
26
|
+
}
|
|
27
|
+
/** מצב הצ'אט עם נציג: queued, active, closed, ticket */
|
|
28
|
+
| {
|
|
29
|
+
type: 'live';
|
|
30
|
+
state: string;
|
|
31
|
+
id: string;
|
|
26
32
|
};
|
|
27
33
|
export interface ScreenDeclaration {
|
|
28
34
|
id: string;
|
|
@@ -86,6 +92,7 @@ export declare class KavchatWidget {
|
|
|
86
92
|
private destroyed;
|
|
87
93
|
/** מחכים לתשובת AI: מציגים "מקליד" ומתעלמים מקלט חדש */
|
|
88
94
|
private waiting;
|
|
95
|
+
private live;
|
|
89
96
|
constructor(options: KavchatOptions);
|
|
90
97
|
/** ה-ShadowRoot, לבדיקות ולאוטומציה באתר המארח */
|
|
91
98
|
get shadowRoot(): ShadowRoot | null;
|
|
@@ -103,6 +110,11 @@ export declare class KavchatWidget {
|
|
|
103
110
|
/** שולח את רשימת המסכים רק כשהשתנתה או פעם בשבוע. שגיאה נבלעת: ננסה שוב בטעינה הבאה */
|
|
104
111
|
private registerScreens;
|
|
105
112
|
private apply;
|
|
113
|
+
/**
|
|
114
|
+
* הצ'אט עם נציג נטען רק כשהוא מופעל בגרסה, או כשיש שיחה פתוחה שמורה. כל mount מקבל בקר חדש,
|
|
115
|
+
* שמשחזר את השיחה מהאחסון. כישלון בטעינה משאיר את הבוט ואת טופס הפנייה כמו שהם
|
|
116
|
+
*/
|
|
117
|
+
private setupLive;
|
|
106
118
|
private restoreSession;
|
|
107
119
|
/**
|
|
108
120
|
* התסריט נבדק בשפת הבוט (מילות עצירה וכו'), והטקסטים הקבועים של הצ'אט מוצגים בשפת הממשק.
|
|
@@ -127,6 +139,7 @@ export declare class KavchatWidget {
|
|
|
127
139
|
private renderMessages;
|
|
128
140
|
private renderChips;
|
|
129
141
|
private showChat;
|
|
142
|
+
/** pre: מה שהמשתמש כבר כתב בבקשה לנציג, ולמה אין נציג (note) */
|
|
130
143
|
private showForm;
|
|
131
144
|
private showSent;
|
|
132
145
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kavchat/widget",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Kavchat web widget: the embeddable scripted support chat for websites.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"prepublishOnly": "yarn build"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@kavchat/core": "0.0.
|
|
28
|
+
"@kavchat/core": "0.0.3"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"esbuild": "^0.28.2",
|