feat: harden support, localize knowledge and add operator availability [skip ci]

Source-only publication of reviewed commit 64e96a7f423673dc29ad56485be9fc79bce8af1c.

Passed in isolation: focused frontend/backend tests, race checks, TypeScript typecheck, lint, Go compilation, Flowgram build, and deterministic SDK build/tests.

Not accepted as a production release: Next.js export/native assembly remains blocked by environment memory limits; browser interaction and MySQL staging acceptance remain unverified. No production server, database/schema, runtime configuration, deployment, release tag, or workflow execution was performed.

Expected source tree: 0a4a7528e9.
This commit is contained in:
2026-10-16 15:21:42 +00:00
parent 299ea50fb5
commit 2f7a491666
176 changed files with 11869 additions and 2716 deletions

View File

@@ -9,7 +9,8 @@ const deferred = () => {
const promise = new Promise((done) => { resolve = done })
return { promise, resolve }
}
const conversation = (id) => ({ id, status: 3, customerUnreadCount: 0 })
const conversation = (id) => ({ id, channelId: 1, status: 3, lastMessageId: 0,
customerUnreadCount: 0, agentUnreadCount: 0, customerLastReadMessageId: 0, agentLastReadMessageId: 0 })
const message = (id, conversationId) => ({ id, conversationId, senderType: "agent",
senderId: 1, messageType: "html", content: "Reply", sendStatus: 1,
customerRead: false, agentRead: false })
@@ -24,6 +25,8 @@ function harness(overrides = {}) {
const config = { channelId: "fixture", externalId: "visitor-1" }
const document = { visibilityState: "visible" }
const api = {
getCustomerIdentityScope: () => JSON.stringify(config),
getCustomerEntryScope: () => JSON.stringify(config),
ensureCustomerSession: async () => ({}),
fetchImWidgetConfig: async () => ({}),
fetchImConversationList: async () => page([conversation(1)]),
@@ -41,6 +44,7 @@ function harness(overrides = {}) {
return { getState: () => state, setState: set }
} },
"@/lib/api/im": api,
"@/lib/message-file-identity": { getMessageFileIdentity: async () => "fixture-file" },
"@/lib/im-realtime": { createImRealtimeConnection: () => {} },
"@/lib/im-message": { summarizeIMMessage: (item) => item.content, parseMessageAssetPayload: () => null },
"@/lib/utils": { generateUUID: () => "fixture" },
@@ -67,9 +71,9 @@ function harness(overrides = {}) {
const compiled = ts.transpileModule(source, { compilerOptions: {
target: ts.ScriptTarget.ES2022, module: ts.ModuleKind.CommonJS,
} })
const module = { exports: {} }
modules.set(name, module.exports)
vm.runInNewContext(compiled.outputText, { module, exports: module.exports,
const moduleContext = { exports: {} }
modules.set(name, moduleContext.exports)
vm.runInNewContext(compiled.outputText, { module: moduleContext, exports: moduleContext.exports,
require: load, console, document, AbortController, WebSocket: { OPEN: 1, CONNECTING: 0 },
setTimeout: (callback, delay) => {
const id = ++nextTimer
@@ -78,10 +82,10 @@ function harness(overrides = {}) {
},
clearTimeout: (id) => timers.delete(id),
})
return module.exports
return moduleContext.exports
}
const store = load("./support-chat.ts").useSupportChatStore
store.setState({ initialized: true, isOpen: true, isVisible: true,
store.setState({ identityScope: api.getCustomerIdentityScope(), initialized: true, isOpen: true, isVisible: true,
conversations: [conversation(1)], conversation: conversation(1), activeConversationId: 1 })
return { store, api, config, document, timers, sent,
get connects() { return connects }, get disconnects() { return disconnects },