Widget chat¶
Thêm bong bóng vào website bằng widget.js. Script mở chat đã xuất bản trong
iframe của Studio; không đưa React vào trang chủ. Để ứng dụng React hiển thị
chat trực tiếp, xem Bộ giao diện React chat.
Xuất bản và cho phép website¶
Xuất bản trang Chat, bật truy cập ẩn danh và/hoặc người dùng bên thứ ba (app),
rồi thêm origin chính xác của website vào Các site được nhúng chat này.
Ví dụ, cho phép https://shop.example.com; origin HTTP localhost cũng dùng được
khi phát triển. Origin khác không thể nhúng trang.
<script src="https://studio.example.com/c/widget.js"
data-slug="support" data-language="vi" data-position="right" async></script>
Snippet data-slug cũ vẫn hoạt động. Bong bóng lưu HMAC của khách ẩn danh trên
website của bạn, dưới khoá superstep-chat:<slug>. Script khác trên website đó
có thể dùng danh tính này, nên chỉ nhúng trên website bạn tin cậy. Khi storage
bị chặn, danh tính chỉ tồn tại trong trang hiện tại. Iframe thuần dùng storage
riêng được trình duyệt phân vùng và có thể bị trình duyệt xoá.
Xếp lệnh trước khi script tải xong¶
<script>
window.Superstep = { q: [
['init', { slug: 'support', open: true, language: 'vi', position: 'right' }],
['on', 'ready', function (event) { console.log(event.slug) }]
] }
</script>
<script src="https://studio.example.com/c/widget.js" async></script>
Có thể dùng mảng tuple: window.Superstep = [['init', { slug: 'support' }]].
Hàng đợi chạy một lần theo thứ tự; đăng ký handler trước sự kiện cần nhận.
Dùng tối đa 100 lệnh trong hàng đợi, rồi gọi API đã tải. Tải script lần nữa sẽ
dùng lại API hiện có. Data attribute được áp dụng trước lệnh trong hàng đợi.
Với hàng đợi inline, áp dụng nonce/hash theo CSP của website.
Đăng nhập người dùng của bạn¶
Backend ký JWT ngắn hạn từ phiên đăng nhập đã xác thực. App secret ở trên server. Xem Xác thực bên thứ ba để biết claim, helper ký token, cách xoay key và mã lỗi.
Có hai cấu hình origin riêng:
| Cấu hình | Ví dụ cho widget này | Mục đích |
|---|---|---|
Chat embed_origins |
https://shop.example.com |
Cho phép website cha nhúng chat và dùng bridge được kiểm tra |
| Origin được phép của app key | https://studio.example.com |
Cho phép HTTP/socket phát ra trong iframe của Studio |
Key chỉ cho phép website cha sẽ từ chối request từ iframe. Client React/headless
trực tiếp dùng origin của ứng dụng. Danh sách origin của key rỗng giữ chính sách
không giới hạn/native. GET cùng origin không có Origin cần Fetch Metadata cùng
origin và referrer thuộc origin của API; cấu hình đúng STUDIO_PUBLIC_URL khi
qua proxy và giữ lại metadata này.
Sau khi API đã tải và ứng dụng chủ đăng nhập thành công:
await window.Superstep.identify(async function () {
const response = await fetch('/api/auth/chat-token', {
method: 'POST', credentials: 'same-origin',
})
const body = await response.json()
if (!response.ok || !body.success) throw new Error('Token request failed')
return body.data.token
})
// Khi đăng xuất ứng dụng chủ, xoá cả danh tính app trong widget:
await window.Superstep.logout()
Endpoint mẫu dùng envelope; điều chỉnh biểu thức trả về nếu endpoint của bạn có
cấu trúc khác. Endpoint phải xác thực và bảo vệ request cấp token, lấy danh tính
trên server, trả Cache-Control: no-store. Không đưa secret, PAT hay workflow
token vào HTML, biến Vite, storage trình duyệt hoặc endpoint cấp token công khai.
identify nhận JWT dạng chuỗi hoặc hàm trả JWT/promise. Nên dùng provider để SDK
lấy token mới và thử lại một lần khi token hết hạn. Gọi lại identify khi đổi
người dùng. Promise hoàn tất khi tải xong lịch sử của người đó, hoặc reject với
code an toàn khi lỗi. logout huỷ danh tính trước và khôi phục lịch sử ẩn danh
của website khi bật truy cập ẩn danh. Provider đang chờ không thể đưa tin nhắn của
người cũ trở lại sau khi đăng xuất/đổi người dùng. Provider/bridge hết thời gian
chờ sau 10 giây với HTTP_ERROR; ứng dụng cần xử lý promise danh tính.
JWT và callback chỉ ở bộ nhớ, không vào URL, storage hay metadata sự kiện công
khai. Bridge nội bộ kiểm tra origin, đúng cửa sổ, channel tài liệu và epoch danh
tính; không tự gửi token qua bridge postMessage dùng wildcard.
API và giao diện¶
| API | Kết quả |
|---|---|
init(options) |
Tạo/cập nhật widget; đổi slug/baseUrl sẽ xoá danh tính app |
open(), close(), toggle() |
Điều khiển khung chat; bong bóng vẫn hiện |
identify(tokenOrGetToken) |
Đổi sang người dùng app và chờ tải lịch sử |
logout() |
Xoá danh tính app và chờ lịch sử ẩn danh |
on(event, handler) |
Đăng ký; trả hàm huỷ đăng ký |
off(event, handler) |
Huỷ đăng ký đó |
init yêu cầu slug. baseUrl mặc định là origin HTTP(S) của script.
Các tuỳ chọn và data attribute:
| Tuỳ chọn | Attribute | Giá trị |
|---|---|---|
open |
data-open |
true để mở sẵn |
language |
data-language (alias data-lang) |
en, vi; mặc định theo trình duyệt |
position |
data-position |
left, right |
color |
data-color |
Màu CSS dùng được cả trong iframe và trên trang chủ |
logo |
data-logo |
URL ảnh HTTP(S) hoặc data URL base64 PNG/JPEG/WebP, tối đa 350.000 ký tự |
Đổi giao diện vẫn giữ chat hiện tại. Chuỗi màu/logo rỗng khôi phục mặc định; giá trị giao diện không hợp lệ bị bỏ qua. Khác provider React, biến CSS của trang chủ không đi qua iframe: cần truyền màu cụ thể. Iframe theo chế độ sáng/tối của trình duyệt. CSP của trang chủ cần cho phép ảnh/script/frame/style liên quan; bong bóng dùng style inline được giới hạn phạm vi.
Sự kiện¶
| Sự kiện | Payload và thời điểm |
|---|---|
ready |
{ slug } sau khi khởi tạo lịch sử và đổi danh tính thành công |
open, close |
{ slug } khi đổi trạng thái hiện; init({open:true}) ban đầu không phát sự kiện |
message, answer |
{ slug, sessionId, turn: { id, role, text, status? } } cho turn người dùng/trợ lý mới được lưu sau khi gửi hoặc trả lời Human |
error |
{ slug, code } khi lỗi khởi tạo danh tính hoặc kết nối |
Khôi phục lịch sử không phát lại sự kiện turn mới. Payload không có frame xác thực, metadata người dùng hay credential file. Subscriber ném lỗi không làm hỏng handler khác. Ví dụ:
const unsubscribe = window.Superstep.on('answer', function (event) {
console.log(event.sessionId, event.turn.id)
})
// Khi không dùng nữa:
unsubscribe()
Thử sample host¶
Chạy scripts/chat_host_e2e.sh từ root của repo. Server mẫu cục bộ cung cấp /
(SDK headless), /react/ và /widget.html. Trang widget dùng lại điều khiển của
portal mẫu và phiên đăng nhập không để lộ dữ liệu; bong bóng/iframe do
widget.js của Studio đã build cung cấp. Thay đăng nhập mẫu trước khi triển
khai ứng dụng của bạn. Phát hành package cần được duyệt riêng.
E2e kiểm tra chat ẩn danh, token do server cấp, hai người dùng/lịch sử, câu trả lời
Human, sự kiện nội dung truyền dần và đăng xuất về danh tính khách ban đầu.
Trường hợp thu hồi key của ví dụ headless chạy cuối trên fixture mới. Bộ kiểm
thử còn kiểm tra từ chối origin, file và đánh giá. Ảnh en/vi/sáng/tối chỉ là
artifact CI tạm thời. Trang /c/<slug>?embed=1 có API trong frame để wrapper
native dùng sau; hướng dẫn theo nền tảng là phần việc riêng.
Sửa tin nhắn đã gửi¶
Các thao tác tin nhắn dùng chung luồng sửa tin nhắn: xác nhận chạy mới trong một nhánh độc lập, giữ nguyên bản gốc và dùng liên kết nguồn để quay lại. Câu trả lời Human không phải tin nhắn gốc được sửa. Với giao diện tự dựng, useChat().edit(turnId, text, operationId) cần cùng bước xác nhận chạy lại; giữ mã thao tác khi phục hồi lần chạy bị gián đoạn. Xem hợp đồng API về tiếp nhận thao tác và phục hồi kết quả.
Tạo lại dùng chung luồng xác nhận tạo nhánh: Tạo lại câu trả lời trên câu trả lời cuối đã kết thúc mở nhánh độc lập và hỏi lại Human/người duyệt. useChat().regenerate(answerId, operationId?) trả kết quả chat thông thường. Xem cách dùng chat và tiếp nhận/phục hồi API.