@microsoft/teams.apps
Version:
<p> <a href="https://www.npmjs.com/package/@microsoft/teams.apps" target="_blank"> <img src="https://img.shields.io/npm/v/@microsoft/teams.apps/latest" /> </a> <a href="https://www.npmjs.com/package/@microsoft/teams.apps?activeTab=code
118 lines • 7.57 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.readField = readField;
exports.isActivityShaped = isActivityShaped;
exports.readEnvelopeActivity = readEnvelopeActivity;
exports.isInvokeEnvelope = isInvokeEnvelope;
exports.replyFrameBase = replyFrameBase;
exports.buildInvokeReplyFrame = buildInvokeReplyFrame;
exports.buildAckReplyFrame = buildAckReplyFrame;
const types_1 = require("./types");
/**
* Read a field from a Teams backend service-serialized object case-insensitively. Teams backend service may encode
* frames with either camelCase or PascalCase depending on the hub protocol, so
* every envelope read goes through this to stay robust to casing changes.
*/
function readField(obj, name) {
if (obj == null || typeof obj !== 'object')
return undefined;
const record = obj;
if (record[name] !== undefined)
return record[name];
const cap = name.charAt(0).toUpperCase() + name.slice(1);
return record[cap];
}
/**
* Whether a value is shaped like a Bot Framework {@link Activity}: a non-null,
* non-array object carrying a string `type`. Used to reject a malformed
* `payload` so it can't be returned as a bogus activity or suppress a valid
* `activity` alias on the same envelope.
*/
function isActivityShaped(value) {
return (value != null &&
typeof value === 'object' &&
!Array.isArray(value) &&
typeof value.type === 'string');
}
/**
* Extract the Bot Framework {@link Activity} from an inbound envelope. Teams backend service
* carries it under `payload` (or `activity` on some builds). Each candidate is
* validated with {@link isActivityShaped}, so a malformed `payload` falls
* through to the `activity` alias instead of masking it.
*/
function readEnvelopeActivity(env) {
const payload = readField(env, 'payload');
if (isActivityShaped(payload))
return payload;
const activity = readField(env, 'activity');
if (isActivityShaped(activity))
return activity;
return undefined;
}
/**
* Whether an envelope represents an invoke activity — which expects a full
* result over client results — versus a one-way activity, which expects a
* post-handler delivery acknowledgement.
*
* Classification is by activity type only: an envelope is an invoke when its
* `type` is `"invoke"`, falling back to the embedded activity's own `type` when
* the envelope carries none. `ackRequired` is a delivery concern (whether the
* caller wants a delivery ack) and deliberately does not affect this shape — an
* invoke must still return its status/body even when an ack was also requested,
* otherwise the invoke result would be silently dropped.
*/
function isInvokeEnvelope(env) {
const type = String(readField(env, 'type') ?? '').toLowerCase();
if (type === 'invoke')
return true;
if (type)
return false;
// No envelope-level type: fall back to the embedded activity type.
const activity = readEnvelopeActivity(env);
return String(activity?.type ?? '').toLowerCase() === 'invoke';
}
/**
* Resolve the common reply-frame fields for an inbound envelope.
* @param botKey the bot's client id, echoed back for Teams backend service routing/validation.
*/
function replyFrameBase(env, botKey) {
return {
envelopeId: readField(env, 'envelopeId'),
botKey,
recvAt: Date.now(),
};
}
/**
* Build the reply frame for an invoke activity from the pipeline's processed
* result. The invoke status/body are returned to Teams backend service over client results.
*/
function buildInvokeReplyFrame(base, response) {
return {
protocolVersion: types_1.SOCKET_MODE_PROTOCOL_VERSION,
envelopeId: base.envelopeId,
botKey: base.botKey,
status: response.status ?? 200,
body: response.body,
recvAt: base.recvAt,
ts: Date.now(),
};
}
/**
* Build the post-handler acknowledgement frame for a one-way activity. Emitted
* only after the handler pipeline has run, so it doubles as a "processed"
* signal — any content reply the handler produced was already sent over HTTP.
*
* @param status delivery status to report; defaults to 200. Passing the
* processed result's status lets a failed handler surface as a non-200 ack.
*/
function buildAckReplyFrame(base, status = 200) {
return {
protocolVersion: types_1.SOCKET_MODE_PROTOCOL_VERSION,
envelopeId: base.envelopeId,
botKey: base.botKey,
status,
recvAt: base.recvAt,
ts: Date.now(),
};
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW52ZWxvcGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc29ja2V0LW1vZGUvZW52ZWxvcGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFhQSw4QkFNQztBQVFELDRDQU9DO0FBUUQsb0RBTUM7QUFjRCw0Q0FPQztBQWdCRCx3Q0FNQztBQWtCRCxzREFVQztBQVVELGdEQVNDO0FBeElELG1DQUlpQjtBQUVqQjs7OztHQUlHO0FBQ0gsU0FBZ0IsU0FBUyxDQUFjLEdBQVksRUFBRSxJQUFZO0lBQy9ELElBQUksR0FBRyxJQUFJLElBQUksSUFBSSxPQUFPLEdBQUcsS0FBSyxRQUFRO1FBQUUsT0FBTyxTQUFTLENBQUM7SUFDN0QsTUFBTSxNQUFNLEdBQUcsR0FBOEIsQ0FBQztJQUM5QyxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxTQUFTO1FBQUUsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFNLENBQUM7SUFDekQsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLEVBQUUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3pELE9BQU8sTUFBTSxDQUFDLEdBQUcsQ0FBa0IsQ0FBQztBQUN0QyxDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxTQUFnQixnQkFBZ0IsQ0FBQyxLQUFjO0lBQzdDLE9BQU8sQ0FDTCxLQUFLLElBQUksSUFBSTtRQUNiLE9BQU8sS0FBSyxLQUFLLFFBQVE7UUFDekIsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQztRQUNyQixPQUFRLEtBQTRCLENBQUMsSUFBSSxLQUFLLFFBQVEsQ0FDdkQsQ0FBQztBQUNKLENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILFNBQWdCLG9CQUFvQixDQUFDLEdBQTJCO0lBQzlELE1BQU0sT0FBTyxHQUFHLFNBQVMsQ0FBQyxHQUFHLEVBQUUsU0FBUyxDQUFDLENBQUM7SUFDMUMsSUFBSSxnQkFBZ0IsQ0FBQyxPQUFPLENBQUM7UUFBRSxPQUFPLE9BQU8sQ0FBQztJQUM5QyxNQUFNLFFBQVEsR0FBRyxTQUFTLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxDQUFDO0lBQzVDLElBQUksZ0JBQWdCLENBQUMsUUFBUSxDQUFDO1FBQUUsT0FBTyxRQUFRLENBQUM7SUFDaEQsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQztBQUVEOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsU0FBZ0IsZ0JBQWdCLENBQUMsR0FBMkI7SUFDMUQsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUUsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDaEUsSUFBSSxJQUFJLEtBQUssUUFBUTtRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQ25DLElBQUksSUFBSTtRQUFFLE9BQU8sS0FBSyxDQUFDO0lBQ3ZCLG1FQUFtRTtJQUNuRSxNQUFNLFFBQVEsR0FBRyxvQkFBb0IsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUMzQyxPQUFPLE1BQU0sQ0FBQyxRQUFRLEVBQUUsSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDLFdBQVcsRUFBRSxLQUFLLFFBQVEsQ0FBQztBQUNqRSxDQUFDO0FBWUQ7OztHQUdHO0FBQ0gsU0FBZ0IsY0FBYyxDQUFDLEdBQTJCLEVBQUUsTUFBZTtJQUN6RSxPQUFPO1FBQ0wsVUFBVSxFQUFFLFNBQVMsQ0FBUyxHQUFHLEVBQUUsWUFBWSxDQUFDO1FBQ2hELE1BQU07UUFDTixNQUFNLEVBQUUsSUFBSSxDQUFDLEdBQUcsRUFBRTtLQUNuQixDQUFDO0FBQ0osQ0FBQztBQWNEOzs7R0FHRztBQUNILFNBQWdCLHFCQUFxQixDQUFDLElBQW9CLEVBQUUsUUFBcUI7SUFDL0UsT0FBTztRQUNMLGVBQWUsRUFBRSxvQ0FBNEI7UUFDN0MsVUFBVSxFQUFFLElBQUksQ0FBQyxVQUFVO1FBQzNCLE1BQU0sRUFBRSxJQUFJLENBQUMsTUFBTTtRQUNuQixNQUFNLEVBQUUsUUFBUSxDQUFDLE1BQU0sSUFBSSxHQUFHO1FBQzlCLElBQUksRUFBRSxRQUFRLENBQUMsSUFBSTtRQUNuQixNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU07UUFDbkIsRUFBRSxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUU7S0FDZixDQUFDO0FBQ0osQ0FBQztBQUVEOzs7Ozs7O0dBT0c7QUFDSCxTQUFnQixrQkFBa0IsQ0FBQyxJQUFvQixFQUFFLFNBQWlCLEdBQUc7SUFDM0UsT0FBTztRQUNMLGVBQWUsRUFBRSxvQ0FBNEI7UUFDN0MsVUFBVSxFQUFFLElBQUksQ0FBQyxVQUFVO1FBQzNCLE1BQU0sRUFBRSxJQUFJLENBQUMsTUFBTTtRQUNuQixNQUFNO1FBQ04sTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNO1FBQ25CLEVBQUUsRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFO0tBQ2YsQ0FBQztBQUNKLENBQUMifQ==