UNPKG

@microsoft/omnichannel-chat-sdk

Version:
106 lines 6.76 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); var TelemetryEvent_1 = require("../telemetry/TelemetryEvent"); var MessageSource_1 = require("../telemetry/MessageSource"); var createOmnichannelMessage_1 = require("./createOmnichannelMessage"); var MAX_TRACKED_STREAMS = 1000; var createOmnichannelStreamingMessage = function (event, params) { var _a, _b, _c, _d, _e, _f; // Drop duplicate finals — log and bail before doing any other work. var incomingType = (_a = event.streamingMetadata) === null || _a === void 0 ? void 0 : _a.streamingMessageType; if (incomingType === 'final' && params.finalizedMessageIds.has(event.id)) { (_b = params.logger) === null || _b === void 0 ? void 0 : _b.recordIndividualEvent(TelemetryEvent_1.default.StreamingDuplicateFinal, MessageSource_1.MessageSource.WebSocketStreaming, { messageId: event.id }); return undefined; } // ACS chunks are typed as ChatMessageEditedEvent; defensively log if the // content field is missing (should be impossible per protocol but the // type system lets it slip through). createOmnichannelMessage handles // the absent-content case by falling back to empty string. if (event.message === undefined || event.message === null) { (_c = params.logger) === null || _c === void 0 ? void 0 : _c.recordIndividualEvent(TelemetryEvent_1.default.StreamingChunkNoContent, MessageSource_1.MessageSource.WebSocketStreaming, { messageId: event.id, eventName: params.eventName }); } // eslint-disable-next-line @typescript-eslint/no-explicit-any var baseMessage = (0, createOmnichannelMessage_1.default)(event, { liveChatVersion: params.liveChatVersion, }); var streamingMetadata = normalizeStreamingMetadata(event, params); if (streamingMetadata.streamingMessageType === 'final') { // LRU-bounded: evict oldest finalized ID when at capacity. if (params.finalizedMessageIds.size >= MAX_TRACKED_STREAMS && !params.finalizedMessageIds.has(event.id)) { var oldestId = params.finalizedMessageIds.values().next().value; if (oldestId !== undefined) { params.finalizedMessageIds.delete(oldestId); (_d = params.logger) === null || _d === void 0 ? void 0 : _d.recordIndividualEvent(TelemetryEvent_1.default.StreamingFinalizedIdEvicted, MessageSource_1.MessageSource.WebSocketStreaming, { evictedMessageId: oldestId }); } } params.finalizedMessageIds.add(event.id); params.sequenceCounters.delete(event.id); } else if (params.finalizedMessageIds.has(event.id)) { // Late chunk after final — log but still emit so consumers can // decide UX behavior. (_e = params.logger) === null || _e === void 0 ? void 0 : _e.recordIndividualEvent(TelemetryEvent_1.default.StreamingChunkAfterFinal, MessageSource_1.MessageSource.WebSocketStreaming, { messageId: event.id }); } // Surface policyViolation (only present on chunk-typed events). var policyViolation = event.policyViolation; if (policyViolation) { (_f = params.logger) === null || _f === void 0 ? void 0 : _f.recordIndividualEvent(TelemetryEvent_1.default.StreamingPolicyViolation, MessageSource_1.MessageSource.WebSocketStreaming, { messageId: event.id, result: policyViolation.result }); } return __assign(__assign(__assign({}, baseMessage), { streamingMetadata: streamingMetadata }), (policyViolation ? { policyViolation: policyViolation } : {})); }; function normalizeStreamingMetadata(event, params) { var _a, _b, _c, _d, _e, _f; var fallbackType = params.eventName === 'streamingChatMessageStarted' ? 'start' : 'streaming'; if (((_a = event.streamingMetadata) === null || _a === void 0 ? void 0 : _a.streamingMessageType) === undefined) { (_b = params.logger) === null || _b === void 0 ? void 0 : _b.recordIndividualEvent(TelemetryEvent_1.default.StreamingMetadataMissingType, MessageSource_1.MessageSource.WebSocketStreaming, { messageId: event.id, eventName: params.eventName }); } // For start events, the event name takes precedence over what ACS sends. // ACS currently sends streamingMessageType: "streaming" even for the start event // (event 250 / streamingChatMessageStarted), so we override to "start". var inferredType = params.eventName === 'streamingChatMessageStarted' ? 'start' : ((_d = (_c = event.streamingMetadata) === null || _c === void 0 ? void 0 : _c.streamingMessageType) !== null && _d !== void 0 ? _d : fallbackType); var inferredSequence = recordAndGetSequence(event, params); var endReason = (_e = event.streamingMetadata) === null || _e === void 0 ? void 0 : _e.streamEndReason; if (inferredType === 'final' && endReason === undefined) { (_f = params.logger) === null || _f === void 0 ? void 0 : _f.recordIndividualEvent(TelemetryEvent_1.default.StreamingFinalMissingReason, MessageSource_1.MessageSource.WebSocketStreaming, { messageId: event.id }); endReason = 'completed'; } return { streamingMessageType: inferredType, streamingSequenceNumber: inferredSequence, streamEndReason: endReason, }; } function recordAndGetSequence(event, params) { var _a, _b, _c; var fromAcs = (_a = event.streamingMetadata) === null || _a === void 0 ? void 0 : _a.streamingSequenceNumber; if (fromAcs !== undefined) { return fromAcs; } // SDK fallback: monotonic counter per messageId, LRU-bounded at MAX_TRACKED_STREAMS. if (params.sequenceCounters.size >= MAX_TRACKED_STREAMS && !params.sequenceCounters.has(event.id)) { var oldestKey = params.sequenceCounters.keys().next().value; if (oldestKey !== undefined) { params.sequenceCounters.delete(oldestKey); (_b = params.logger) === null || _b === void 0 ? void 0 : _b.recordIndividualEvent(TelemetryEvent_1.default.StreamingCounterEvicted, MessageSource_1.MessageSource.WebSocketStreaming, { evictedMessageId: oldestKey }); } } var next = ((_c = params.sequenceCounters.get(event.id)) !== null && _c !== void 0 ? _c : 0) + 1; params.sequenceCounters.set(event.id, next); return next; } exports.default = createOmnichannelStreamingMessage; //# sourceMappingURL=createOmnichannelStreamingMessage.js.map