Skip to content

Release 2.0.12: merge main into release (QR included)#600

Merged
corinagum merged 32 commits into
releasefrom
prep-release/2.0.12
May 27, 2026
Merged

Release 2.0.12: merge main into release (QR included)#600
corinagum merged 32 commits into
releasefrom
prep-release/2.0.12

Conversation

@corinagum
Copy link
Copy Markdown
Collaborator

Summary

Brings origin/main into release for the 2.0.12 release. No carve-outs this time — Quoted Replies is included.

version.json: 2.0.12-preview.{height}2.0.12.

Aligns with teams.py 2.0.12 (PR #442 already on PyPI / pending publish).

What's in this release (delta from 2.0.11)

Features

Security & fixes

Deprecations / package changes

Dependency bumps

Quoted Replies inclusion notes

  • Teams client rendering is in-sync with the wire format as of 2026-05-06.
  • APX QR rollout completed: Public 2026-04-10, GCCH/DoD/Gallatin 2026-04-14.
  • No SDK-side carve-outs needed; this matches the teams.py 2.0.12 (PR Upgrade to express v5 #442) decision.

Branch structure note

prep-release/2.0.12 is reset to origin/main + a one-line version.json bump. Diff against release (this PR) shows the full delta from 2.0.11. We deliberately did not use a 2-parent merge commit — the auto-merge tried to interleave non-overlapping hunks from main's QR additions with release's QR carve-outs in activity.ts, producing a semantically broken file. Reset-to-main + version bump is the clean way to express "release should equal main."

Test plan

  • npm install clean (post-audit-fix lockfile)
  • npm run build — 33/33 targets clean
  • npm test — 14/14 task targets, 279+ tests pass
  • E2E echo bot smoke test against cg-test-bot-py via canary ABS — done on cg/audit-deps-ts (now merged); covers axios + msal-node code paths
  • Pipeline Build + Test stages green on release after merge
  • Publish pipeline run with Public → ESRP → npm @microsoft/teams.*@2.0.12
  • Smoke install: npm view @microsoft/teams.apps@2.0.12 after publish

heyitsaamir and others added 30 commits May 6, 2026 14:22
Bumps the patch version on main for the next preview release cycle
following the 2.0.10 stable release. Per RELEASE.md step 4.
## Problem

The release pipeline fails on `npm ci` with errors like:

```
npm error Missing: turbo-windows-arm64@2.8.11 from lock file
npm error Missing: @esbuild/win32-arm64@0.25.12 from lock file
...
```

## Root cause

The pipeline's `NodeTool@0` task uses `versionSpec: '24.x'`, which
provisions Node 24 + **npm 11**. However:

- This repo pins `"packageManager": "npm@10.8.1"` in `package.json`.
- npm 10 only records platform-specific optional dependencies for the
**current** platform when generating `package-lock.json` (so a lockfile
generated on macOS only contains Mac binaries for `@esbuild/*` and
`turbo-*`).
- npm 11 requires **all** platform binaries to be present in the
lockfile and treats missing ones as out-of-sync, failing `npm ci`.

Lockfile is valid under npm 10 — `npm ci` succeeds locally. The mismatch
is purely between the pipeline's npm and the project's pinned npm.

## Fix

Pin the pipeline to Node 22 (LTS), which ships with npm 10, matching the
`packageManager` field and every developer's local environment.

## Alternative considered

Bumping the project to npm 11 (update `packageManager`, regenerate
lockfile under npm 11, force every dev to upgrade). Rejected as larger
blast radius for an unblock-the-release fix.

## Follow-up

This same change needs to be cherry-picked to `release` to unblock the
2.0.10 publish.
## Summary

Addresses security scan finding #14 (MCP server mounted without auth).
TypeScript half of a 2-SDK PR set (.NET PR is on the same branch name).

> **Note:** Earlier revisions of this branch also addressed finding #15
(MCP client URL validation). #15 has been dropped — the SSRF risk
against MCP client URLs is low-likelihood and the default
private-network filter created friction for legitimate on-prem MCP
customers. Reverted in commit `fd3444f8`.

## #14 — MCP server auth

New opt-in `requireAuth` hook on `McpPluginOptions`:

```ts
new McpPlugin({
  requireAuth: (req) => req.headers.authorization === 'Bearer ...'
})
```

Hook is called once per inbound MCP request via an Express-level prefix
middleware on `/mcp` (covers any current or future handler registered
under that path). `false`/throw returns 401. When unset, all requests
are accepted and a one-time startup warning fires when the SSE transport
comes up.

## Design doc

`design/mcp-server-auth-options.md`

## E2E verified

- Middleware gating: `/mcp` returns 401 without auth, SSE handshake on
correct bearer
- Activity path (`/api/messages`): bot responded to a devtools chat
message with `REQUIRE_AUTH=1` active simultaneously
- Startup warning fires when `requireAuth` is unset; silent when set

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
<img width="800" height="234" alt="image"
src="https://github.com/user-attachments/assets/4bc04524-944a-4c59-a3a4-7e9c50076f44"
/>

- Remove `withReplyToId()`: `replyToId` body property has no effect on
threading (APX only uses it for encryption)
- Add `QuotedReplyEntity` type with nested `quotedReply` data object
(`messageId` required,
`senderId`/`senderName`/`preview`/`time`/`isReplyDeleted`/`validatedMessageReference`
optional)
- Add `getQuotedMessages()` on `MessageActivity` to read inbound quoted
reply entities
- Add `addQuotedReply(messageId, response?)` builder on
`MessageActivity` for constructing outbound quotes (build order =
reading order)
- Update r`eply()` to stamp `quotedReply` entity `+ <quoted
messageId="..."/>` placeholder instead of blockquote HTML; remove
`replyToId` assignment
- Add `quoteReply(messageId, activity)` on `ActivityContext` for quoting
arbitrary messages
- Mark all quoted reply types and methods as `@experimental`
- Fix bug in `ActivityContext` constructor where `Object.assign(this,
rest)` ran before `MessageActivity.from().toInterface()`, causing
interface methods (`getQuotedMessages`, `stripMentionsText`,
`isRecipientMentioned`, `getAccountMention`) to be missing on
`context.activity`. Added regression test.
- Add quoted-replies example exercising all APIs

---------

Co-authored-by: Corina Gum <>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bumps [hono](https://github.com/honojs/hono) from 4.12.14 to 4.12.16.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/honojs/hono/releases">hono's
releases</a>.</em></p>
<blockquote>
<h2>v4.12.16</h2>
<h2>Security fixes</h2>
<p>This release includes fixes for the following security issues:</p>
<h3>Unvalidated JSX Tag Names in hono/jsx May Allow HTML Injection</h3>
<p>Affects: hono/jsx. Fixes missing validation of JSX tag names when
using <code>jsx()</code> or <code>createElement()</code>, which could
allow HTML injection if untrusted input is used as the tag name.
GHSA-69xw-7hcm-h432</p>
<h3>bodyLimit() can be bypassed for chunked / unknown-length
requests</h3>
<p>Affects: Body Limit Middleware. Fixes late enforcement for request
bodies without a reliable Content-Length (e.g. chunked requests), where
oversized requests could reach handlers and return successful responses
before being rejected. GHSA-9vqf-7f2p-gf9v</p>
<h2>v4.12.15</h2>
<h2>What's Changed</h2>
<ul>
<li>fix(jwt): support single-line PEM keys by <a
href="https://github.com/hiendv"><code>@​hiendv</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/4889">honojs/hono#4889</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/hiendv"><code>@​hiendv</code></a> made
their first contribution in <a
href="https://redirect.github.com/honojs/hono/pull/4889">honojs/hono#4889</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/honojs/hono/compare/v4.12.14...v4.12.15">https://github.com/honojs/hono/compare/v4.12.14...v4.12.15</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/honojs/hono/commit/90d4182aabd328e2ec6af3f25ec62ddc574ad8cb"><code>90d4182</code></a>
4.12.16</li>
<li><a
href="https://github.com/honojs/hono/commit/db05b96d7a4de569ba9e965052b0593663b164fc"><code>db05b96</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/honojs/hono/commit/614b834551378bffff70c810b2295495bc6e4d55"><code>614b834</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/honojs/hono/commit/027e3dfca9d58bbd6b2e11adef724d26bb4f4123"><code>027e3df</code></a>
fix(method-override): handle Content-Type with charset parameter (<a
href="https://redirect.github.com/honojs/hono/issues/4894">#4894</a>)</li>
<li><a
href="https://github.com/honojs/hono/commit/f774f8df49e7ec7e205f15c5076a37132c515ebf"><code>f774f8d</code></a>
4.12.15</li>
<li><a
href="https://github.com/honojs/hono/commit/18fe604c8cefc2628240651b1af219692e1918c1"><code>18fe604</code></a>
fix(jwt): support single-line PEM keys (<a
href="https://redirect.github.com/honojs/hono/issues/4889">#4889</a>)</li>
<li>See full diff in <a
href="https://github.com/honojs/hono/compare/v4.12.14...v4.12.16">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=hono&package-manager=npm_and_yarn&previous-version=4.12.14&new-version=4.12.16)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/microsoft/teams.ts/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Refresh the lock file to ensure dependencies are up to date.

---------

Co-authored-by: heyitsaamir <ajawaid191@gmail.com>
While setting up some sample projects to repro & test a fix for bug 542,
I realized that on older webpack I had to add babel configuration to
work around subpath imports inside of the teams.ts libraries. I had to
add the alias section here to my webpack.frontend.config.js just for a
basic tab test app. Which is doable, but also unnecessary friction:
```
  resolve: {
    extensions: [".tsx", ".ts", ".js"],
    mainFields: ["main", "module", "browser"],
    alias: {
      "@microsoft/teams.common/http$": path.resolve(
        __dirname,
        "node_modules/@microsoft/teams.common/dist/http/index.js"
      ),
      "@microsoft/teams.common/logging$": path.resolve(
        __dirname,
        "node_modules/@microsoft/teams.common/dist/logging/index.js"
      ),
    },
  },
``` 

In addition, I noticed that we often use wildcard imports for
readability, but on older bundlers this may impact tree shakability.

Let's clean up both of these and switch to named imports without
subpaths. There are no code changes from this, just a bunch of routine
imports & type alias changes.

How tested:
- Built & packed the packages locally; npm installed them into my test
project; verified that I could now remove the alias section
 - Build passes, linter passes, unit tests pass.
- Verified that the diffs detected by Template Sync Verification are
false positives, as they didn't have the same imports in the first
place. skip-test-verification
…t react project: Module has no exports. (#566)

This PR addresses [bug
542](#542). by adding an
onSuccess handler to the tsup.config.js to rewrite .mjs import paths to
be compliant with the ESM specification.

Webpack 5 strictly requires that ESM code follows specification and
includes a file extension on import paths. Other bundlers - Webpack 4,
RSPack, Vite/Rollup - are more forgiving, but benefit from code
following specification.

Tsup that we're using in these libraries doesn't automatically produce
compliant import statements, but we can take care of that with an
onSuccess handler to call a script and update the import paths. This was
already done for the graph-endpoints package that doesn't use tsup at
all, and makes sense to do for the tsupped code also.

Before the change in this PR, a React app using these libraries and
relying on Webpack 5 would fail during build with e.g.:

```
building with released bits, webpack 5:
WARNING in ./src/Tab/App.tsx 35:28-41
export 'ConsoleLogger' (imported as 'ConsoleLogger') was not found in '@microsoft/teams.common' (module has no exports)
 @ ./src/Tab/client.tsx 4:0-24 5:85-88

ERROR in ./node_modules/@microsoft/teams.client/dist/index.mjs 1:0-28
Module not found: Error: Can't resolve './app' in 'C:\git\TeamsApps\webpack5app\node_modules\@microsoft\teams.client\dist'
Did you mean 'app.js'?
BREAKING CHANGE: The request './app' failed to resolve only because it was resolved as fully specified
(probably because the origin is strict EcmaScript Module, e. g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains '"type": "module"').
The extension in the request is mandatory for it to be fully specified.
Add the extension to the request.
 @ ./src/Tab/App.tsx 4:0-64 34:35-49
 @ ./src/Tab/client.tsx 4:0-24 5:85-88
```

Before the change, after building these libraries, import paths in .e.g
packages/common/dist/index.mjs would look like:
```
export * from './events';
export * from './http';
export * from './logging';
export * from './storage';
```
After, they're correctly
```
export * from './events/index.mjs';
export * from './http/index.mjs';
export * from './logging/index.mjs';
export * from './storage/index.mjs';
```

Similarly, before the change, packages/common/dist/http/client.mjs
contained:
```
import { ConsoleLogger } from '../logging';
```
And now it's correctly:
```
import { ConsoleLogger } from '../logging/index.mjs';
```

How tested:
- Built from the project root as well as within an individual package
and verified that the import paths are correctly rewritten in the dist
folder.
 - Built on both Mac and WIndows and looked at the dist folder.
- Set up a simple Teamss tab app using these libraries to use teams-js
context / msal / graph.
- Before the change: verified that I can build the app with vite/rollup,
rspack, and webpack 4; but webpack 5 fails as above
- After the change, verified that I can build using all four and that
the app still runs
- After the change, also verified that the app tree-shakes properly on
all four. Vite gives best results; webpack 4 the worst, but they all do
their level best
## Summary

Renames the experimental `ReactionClient.remove()` method to `delete()`
to align with the equivalents in teams.py (`delete()`) and teams.net
(`DeleteAsync()`). The cross-SDK naming inconsistency was the only
divergence in the reactions API surface.

The `ReactionClient` class is annotated
`@experimental("ExperimentalTeamsReactions")`. This rename is within the
breaking-change contract for that diagnostic, so no back-compat alias is
added.

## Changes

- `packages/api/src/clients/reaction/reaction.ts` — method rename +
JSDoc
- `packages/api/src/clients/reaction/reaction.spec.ts` — updated test
names and call sites
- `packages/api/src/activities/message/message-reaction.ts` —
`@deprecated` JSDoc on the activity helper now points to
`api.reactions.delete`
- `examples/reactions/src/index.ts` — usage updated
- `examples/reactions/README.md` — usage updated, plus refreshed the
reaction-types list that was still showing legacy Bot Framework types
(`laugh`, `surprised`, `sad`, `angry`) instead of the modern Teams set
the SDK actually exports

## Test plan

- [x] `npx turbo test --filter=@microsoft/teams.api` passes (17/17
suites, 145/145 tests; reaction.ts at 100% coverage)
- [x] Smoke-run the reactions example bot

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Prompt preview allows a bot to reference the original targeted message
in its reply, so Teams can render a collapsible preview of the user's
prompt.

When a bot replies to a targeted message (reactive scenarios), the SDK
now passes the original message's messageId via a targetedMessageInfo
entity in the activity's entities array.

For proactive replies, developers can attach the entity themselves with
the messageId of the targeted message.
## Summary
Adds defensive null checks to prevent crashes when accessing message
properties on empty or boundary arrays.

## Changes
- Added `len > 0` guard before array access in trim loop
- Added optional chaining (`?.`) for `messages[0].role` access
- Added `last &&` guard and bounds check in slice operation

## Testing
- Verified with ESLint (passes)
- Prevents crash when memory is empty or during edge-case trimming

Fixes #2500, #2503

---------

Co-authored-by: claude-swarm-agent <swarm@local>
Co-authored-by: Corina Gum <14900841+corinagum@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## Summary

Removes the `@experimental` JSDoc tags from `ReactionClient`,
`MessageReactionType`, `MessageReaction`, and the `reactions` property
on `ApiClient`. The reactions feature is in sync across all three SDKs
and the Teams service — no longer preview.

Also fixes the sample's `remove` command, which previously called
`api.reactions.delete()` on an incoming message that had no reaction. It
now adds the reaction first, waits 2 seconds, then deletes — so the demo
visibly shows the full add/delete cycle.

## Cross-SDK coordination

Part of the cross-SDK Reactions-GA pass. Sibling PRs:
- microsoft/teams.py — Mark reactions API as GA
- microsoft/teams.net — Mark reactions API as GA (Libraries + core)
- microsoft/teams-sdk — drop .NET opt-in tip from the reactions guide

## Test plan

- [x] `npm run lint` — 34/34 packages clean
- [x] `npm run build` — 35/35 packages succeed
- [x] `npm run test` — 746/746 tests pass across 61 suites (api at
149/149)
- [ ] Smoke run of `examples/reactions` showing the cycle in Teams

## Versioning

No `version.json` change in this PR. Bump happens as part of the release
flow per RELEASE.md.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
- Fix App client option handling so custom `User-Agent` values get
merged instead of stomped.
- Add a regression test for lowercase `user-agent` 

## Test plan
- UTs
This pull request introduces a new sample bot, `ai-mcp`, which
demonstrates integrating Azure OpenAI with the Model Context Protocol
(MCP) in Microsoft Teams. The changes include a new codebase, updated
documentation, and configuration to highlight streaming responses,
per-conversation memory, clarification cards, MCP tool integration,
inline citations, follow-up suggestions, and custom feedback. The sample
replaces the previous `ai` example with a more advanced, MCP-enabled
version.

Breaking Change:
PY and TS previously diverged in the way they added attachments,
entities, etc to their final message activity in streaming. PY uses the
final activity to build these (discarding any previous ones), introduced
in this specific commit
-microsoft/teams.py@7d5b445#diff-cfe4ab75f0e2e0cb406509120bf35f7f58362130916d7f08d85ac7d88de29b62.
TS was previously accumulating it across all streaming activities but
behavior now changes to reflect PY.

Key changes:

**New ai-mcp Sample Implementation**

* Added a new sample bot in `examples/ai-mcp` that integrates Azure
OpenAI and MCP, showcasing advanced Teams bot features such as
streaming, tool-calling, inline citations, and feedback. The sample
includes core files: `agent.ts` (agent logic and tool loop),
`citation-collector.ts` (citation extraction and attachment),
`handlers.ts` (Teams activity routing), and a detailed `README.md`
explaining architecture and usage.
[[1]](diffhunk://#diff-9b3bc8bc9802a22deda9c3fceec841c184029a34ebd530461baa2331a6f039a8R1-R201)
[[2]](diffhunk://#diff-e67849ae74099e714b7a68ed0ea879ca74a4705869ab1fdfe66dd1a10f414d62R1-R109)
[[3]](diffhunk://#diff-5a78ce0e8c05544622dd15d9dfb3f3cc9c9d8986374221978068249612a8fd04R1-R138)
[[4]](diffhunk://#diff-7cc47f84a147fb8a94e4a6c79588ebc13c068bccff8e2e087fe70f7bd8ea4b77R1-R93)

**Project and Manifest Updates**

* Renamed the package and manifest from `ai` to `ai-mcp`, updated bot
name and descriptions in `package.json` and `appPackage/manifest.json`
to reflect the new MCP-enabled sample.

**Dependency Changes**

* Removed legacy dependencies related to the old sample and added new
dependencies: `@modelcontextprotocol/sdk` and `openai`, which are
required for MCP and Azure OpenAI integration.

These changes collectively deliver a more feature-rich Teams bot sample
that demonstrates modern AI and MCP integration patterns.

---------

Co-authored-by: Copilot <copilot@github.com>
This pull request refactors and improves the a2a Teams bot sample to
support a symmetric "Alice and Bob" handoff scenario, where two bots can
hand users off to each other using the A2A protocol. The changes
introduce per-bot configuration, update dependencies, add clear
documentation, and implement robust A2A client/server logic for
proactive handoffs.

**Key changes include:**

### New features and architecture

* Added support for two symmetric bots ("Alice" and "Bob") with separate
`.env` templates, configuration, and scripts. Each bot can listen on its
own port and hand off to the other. (`.env.alice.template`,
`.env.bob.template`, `package.json`, `README.md`)
[[1]](diffhunk://#diff-df7cf90c0e00b8fd76a91e6a50f9c2bc94e0ba1220794185acb4f7cb556be5bbR1-R21)
[[2]](diffhunk://#diff-aaefa6c0d8b239bc9feede8f50a8b7936896c98e1935e581c09aad67c52c8f1cR1-R17)
[[3]](diffhunk://#diff-7ba42913b3f1e8a72e627a307bb18f8d3cff19ce5bf2a164da522b0902a85885L18-R36)
[[4]](diffhunk://#diff-b45bac4007d36d313c72aea6e1390368a7e46001dec982a3d0818cab67b6e29cL1-R127)
* Implemented an outbound A2A client (`A2APeerClient` in
`src/a2a-client.ts`) that resolves the peer's live AgentCard and sends
handoff messages as DataParts.
* Implemented an inbound A2A server executor (`HandoffAgentExecutor` in
`src/a2a-server.ts`) that receives handoffs, opens a proactive 1:1 DM
with the user, seeds conversation history, and sends a greeting using
the LLM.

### Configuration and scripts

* Added `.env.alice` and `.env.bob` to `.gitignore` for local, per-bot
configuration.
* Updated `package.json` scripts for per-bot development (`dev:alice`,
`dev:bob`) and switched to a unified entrypoint. Updated and added
dependencies for the new architecture.
* Reset the package version to `0.0.1` for the new sample structure.

### Documentation

* Overhauled `README.md` to clearly explain the dual-bot handoff
scenario, configuration steps, flow, caveats, and how to run the sample.

### Cleanup

* Removed the old `CHANGELOG.md` as part of the sample reset.

Overall, these changes provide a clear, modern, and easily configurable
sample for demonstrating proactive A2A handoffs between two Teams bots.
Updates the `targeted-messages` example manifest to opt into slash
commands per the docs spec (microsoft/teams-sdk#2843,
MicrosoftDocs/msteams-docs#14182), and adds a handler that demonstrates
how slash commands surface to the bot.

## Changes

- **`examples/targeted-messages/appPackage/manifest.json`**:
- Bump `$schema` and `manifestVersion` to `devPreview` (the
slash-commands opt-in fields are only defined in the devPreview schema
today).
- Add `bots[].supportsTargetedMessages: true` to opt the bot into
receiving slash-command-style targeted messages.
- Add `bots[].commandLists[].triggers: ["slash"]` declaring `test send`
/ `test update` / `test delete` / `test public` / `test inbound` as
slash commands surfaced in the Teams `/` picker (scoped to `team` and
`groupChat`).
- **`examples/targeted-messages/src/index.ts`** — new `test inbound`
handler that reads `activity.recipient?.isTargeted` and reports whether
the inbound message was delivered as a targeted message (the signal
slash commands arrive with).
- **`examples/targeted-messages/README.md`** — refreshed commands table,
new "Manifest configuration" section documenting the new fields.

## Test plan

- [x] `npx turbo build --filter=@examples/targeted-messages` clean
- [x] `examples/targeted-messages/appPackage/manifest.json` validates
against the Teams devPreview schema (placeholder `${{...}}` tokens
excepted)
- [x] Sample bot's `test inbound` handler verified live in Teams:
broadcast branch fires when the inbound is not targeted (the targeted
branch will fire once slash commands start delivering with
`recipient.isTargeted = true`)

🤖 Generated with [Claude Code](https://claude.com/claude-code)
This pull request deprecates several internal packages and updates
documentation to guide users toward using dedicated third-party SDKs
directly. It also removes the `examples/lights` example and all its
related files, reflecting a shift in recommended development patterns
for AI and agent integrations.

Deprecation of internal packages and guidance for migration:

* Marked the following packages as deprecated: `@microsoft/teams.ai`,
`@microsoft/teams.openai`, `@microsoft/teams.mcp`,
`@microsoft/teams.mcpclient`, and `@microsoft/teams.a2a`. Updated their
`README.md`, `package.json`, and entry points to include deprecation
notices and migration instructions to use open-source SDKs like
`openai`, `@modelcontextprotocol/sdk`, and `@a2a-js/sdk` directly.
[[1]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L82-R90)
[[2]](diffhunk://#diff-8c59905f0ee8eed78b9a07dbf68d19f7f11eff4c527796bf7223421b9b39086eR3-R4)
[[3]](diffhunk://#diff-421d48731716c0c802b01b0e9a14a58396848800215cf072767d971011f676f3R5)
[[4]](diffhunk://#diff-56e869667b5013e86a0f58069ecf1806b1a41cfda4dcb6f1de42c27d0f3c5772R1-L4)
[[5]](diffhunk://#diff-95112006e78f470c720e81744809e835c31ce1d7be37b89f9a9046c5de590e45R3-R4)
[[6]](diffhunk://#diff-e33505cb513eaeee16e702fac92ed29e4dc6957e75dfd05e13559a9afe20899eR5)
[[7]](diffhunk://#diff-216185d88d1ced77f6d6478f9bd7f2afab14e5cd09f1e9e90c18979914d4d9f9R1-R5)
[[8]](diffhunk://#diff-c9eb2a32a74cf979ad0504fa8a6889c7c9283d6e0424811bb08f50a9a0663e44R3-R4)
[[9]](diffhunk://#diff-df799685adf6a348b6e6e5692d7860a01632cb0da43fac3add341d24f1fdc424R5)
[[10]](diffhunk://#diff-90aca77e00279d875b47610d3fb44e2f61ca74c4932cf0f717aee6df7f1d16b9R1-R5)

Documentation and example updates:

* Updated the main `README.md` to move deprecated packages to a new
section with clear migration paths and added references to new example
apps (`examples/ai-mcp`, `examples/a2a`) that demonstrate the preferred
integration approach.
[[1]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L69)
[[2]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L82-R90)
[[3]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L104-R106)
* Added prominent deprecation warnings to the documentation of affected
packages, ensuring users are aware of the new recommendations.
[[1]](diffhunk://#diff-8c59905f0ee8eed78b9a07dbf68d19f7f11eff4c527796bf7223421b9b39086eR3-R4)
[[2]](diffhunk://#diff-95112006e78f470c720e81744809e835c31ce1d7be37b89f9a9046c5de590e45R3-R4)
[[3]](diffhunk://#diff-c9eb2a32a74cf979ad0504fa8a6889c7c9283d6e0424811bb08f50a9a0663e44R3-R4)

Removal of the `examples/lights` example:

* Deleted the entire `examples/lights` directory, including source code,
configuration, changelog, and documentation, as this example relied on
deprecated patterns.
[[1]](diffhunk://#diff-c647ca68b7685b69d995cdffc8da39cf6f02bc2de8711d4194536000606fe8fbL1-L279)
[[2]](diffhunk://#diff-edfbbd6ef6e0254fead35df658fb85e5df21bbac4ed33016e881cd9096b2a592L1-L9)
[[3]](diffhunk://#diff-b3218b9b551e31b41185e2c65b46610d42ca65f3b13599e668926b989537b2ccL1)
[[4]](diffhunk://#diff-6546e5573b17689b6d50f5d4d05108f19fc960090caab5173a23b7987d1fee24L1-L34)
[[5]](diffhunk://#diff-3109f39824a23d83d383e41b5eaacb38f68b448a864765f009ef636a4c9fac52L1-L120)
[[6]](diffhunk://#diff-46cfbb85729b711c8a376efb75d1bc2cc98bda6528fe8a3aed9d1a90dc58952dL1-L8)
[[7]](diffhunk://#diff-47750164dcf7d7187691e0760324465b36bb8a8b9e05183931f8ff8e351a0aeeL1-L20)
[[8]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L104-R106)

Build and dependency configuration cleanup:

* Updated build dependencies in `examples/mcp-server/turbo.json` to
remove references to deprecated packages, ensuring only supported
packages are built.

These changes help clarify the project's direction, encourage best
practices by leveraging dedicated SDKs, and reduce maintenance overhead
by removing deprecated code and examples.

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This PR is in preparation of adding additional linter rules. There are
no functional changes here, but I'm enabling isolatedDeclarations and
isolatedModules to a bunch of smaller packages; rearranging imports to
favor import as type whenever feasible, and adding return type
annotations where missing. This helps reduce build time a smidge and
provides better inputs for any tools consuming these libraries - e.g.
for tree shaking or transpiling.

How tested:
 - The code builds; linter and unit tests pass
- I built & packaged the libraries and used them in a separate
playground app to make sure it still builds and runs fine.
## Summary

Documents the layered authentication model the SDK uses for inbound JSON
Web Tokens. TypeScript half of a 3-SDK PR set.

## Why

Security scan finding "JsonWebToken No Signature Verification" flagged
the `JsonWebToken` accessor class for decoding tokens without verifying
signatures. A cross-SDK audit confirmed this is intentional
architecture: signature verification runs at the HTTP boundary
(`JwtValidator.validateAccessToken` in
`packages/apps/src/middleware/auth/`), and the accessor exists as a
typed view over already-validated payloads. Every consumer of decoded
claims is downstream of a validator pass.

This PR makes the architectural invariant explicit at the constructor
site so future readers (and the scanner on its next pass) see the design
intent locally.

## What

Contract docstring at `JsonWebToken`'s constructor explaining that it
performs no signature verification, where verification actually happens,
and the rule that callers must not construct from raw network input.

## What this does not change

- No runtime behavior change. No signature verification added or
removed.
- No API surface change. `JsonWebToken` keeps its current name and shape
(verified public on `@microsoft/teams.api`, so a rename would have been
breaking).
- No effect on the activity pipeline. Bot Framework JWT validation
continues to happen via `JwtValidator.validateAccessToken` exactly as
before.

## Related PRs

- Python: microsoft/teams.py#432
- .NET: microsoft/teams.net#517
- Documentation: microsoft/teams-sdk#2850
## Summary
- make `send` / `reply` default to targeted when replying to a targeted
inbound message
- keep explicit public sends, different recipients, and different
conversation refs public
- split the targeting logic into helpers so the rules are less spicy
- keep `targetedMessageInfo` limited to targeted inbound replies, so
normal explicit targeted sends still work
- add targeted-messages example commands for `send private` and `send
public`

Note: this also cleans up a pre-existing dead branch from when
`isTargeted` moved onto `recipient` — `params.recipient?.isTargeted`
already means `params.recipient` exists.

<img width="943" height="571" alt="image"
src="https://github.com/user-attachments/assets/dd828854-3d32-4617-9eb3-3b32c17dbe75"
/>


## Test plan
- `cd packages/apps && npx jest src/contexts/activity.test.ts
--runInBand`
- `cd packages/apps && npm run build`
- `cd examples/targeted-messages && npm run build`
Adds support for suggestedActions/submit invoke activity - dispatched by
the platform when a user clicks an Action.Submit suggested-action click.

- New `ISuggestedActionSubmitInvokeActivity` interface and
`suggested-action.submit` route alias.
- New `Action.Submit` value in CardActionType for constructing outbound
suggested-action chips.
- Marked `@experimental` until the platform feature stabilizes. 
- New examples/suggested-actions sample app.

<img width="1017" height="243" alt="image"
src="https://github.com/user-attachments/assets/12861bfd-73a0-4337-a917-500825ace815"
/>
Bumps [qs](https://github.com/ljharb/qs) from 6.15.0 to 6.15.2.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/ljharb/qs/blob/main/CHANGELOG.md">qs's
changelog</a>.</em></p>
<blockquote>
<h2><strong>6.15.2</strong></h2>
<ul>
<li>[Fix] <code>stringify</code>: skip null/undefined entries in
<code>arrayFormat: 'comma'</code> + <code>encodeValuesOnly</code>
instead of crashing in <code>encoder</code></li>
<li>[Fix] <code>stringify</code>: use configured <code>delimiter</code>
after <code>charsetSentinel</code> (<a
href="https://redirect.github.com/ljharb/qs/issues/555">#555</a>)</li>
<li>[Fix] <code>stringify</code>: apply <code>formatter</code> to
encoded key under <code>strictNullHandling</code> (<a
href="https://redirect.github.com/ljharb/qs/issues/554">#554</a>)</li>
<li>[Fix] <code>stringify</code>: skip null/undefined filter-array
entries instead of crashing in <code>encoder</code> (<a
href="https://redirect.github.com/ljharb/qs/issues/551">#551</a>)</li>
<li>[Fix] <code>parse</code>: handle nested bracket groups and add
regression tests (<a
href="https://redirect.github.com/ljharb/qs/issues/530">#530</a>)</li>
<li>[readme] fix grammar (<a
href="https://redirect.github.com/ljharb/qs/issues/550">#550</a>)</li>
<li>[Dev Deps] update <code>@ljharb/eslint-config</code></li>
<li>[Tests] add regression tests for keys containing percent-encoded
bracket text</li>
</ul>
<h2><strong>6.15.1</strong></h2>
<ul>
<li>[Fix] <code>parse</code>: <code>parameterLimit: Infinity</code> with
<code>throwOnLimitExceeded: true</code> silently drops all
parameters</li>
<li>[Deps] update <code>@ljharb/eslint-config</code></li>
<li>[Dev Deps] update <code>@ljharb/eslint-config</code>,
<code>iconv-lite</code></li>
<li>[Tests] increase coverage</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/ljharb/qs/commit/9aca4076fe788338c67cf7e115f0be6bc58d85a8"><code>9aca407</code></a>
v6.15.2</li>
<li><a
href="https://github.com/ljharb/qs/commit/5e33d33447ed0bf1ddab9abc41d27dea4687d992"><code>5e33d33</code></a>
[Dev Deps] update <code>@ljharb/eslint-config</code></li>
<li><a
href="https://github.com/ljharb/qs/commit/21f80b33e5c8b3f7eba1034fff0da4a4a37a1d41"><code>21f80b3</code></a>
[Fix] <code>stringify</code>: skip null/undefined entries in
<code>arrayFormat: 'comma'</code> + `e...</li>
<li><a
href="https://github.com/ljharb/qs/commit/a0a81ea2071acce3eff41a040f719ac8f5c4f64c"><code>a0a81ea</code></a>
[Fix] <code>stringify</code>: use configured <code>delimiter</code>
after <code>charsetSentinel</code></li>
<li><a
href="https://github.com/ljharb/qs/commit/e3062f78f5233b338ceeb8e8dfa5a07dea4b32a8"><code>e3062f7</code></a>
[Fix] <code>stringify</code>: apply <code>formatter</code> to encoded
key under <code>strictNullHandling</code></li>
<li><a
href="https://github.com/ljharb/qs/commit/0c180a40adb8c6703fffc85b2ff06ca209f5c1e0"><code>0c180a4</code></a>
[Fix] <code>stringify</code>: skip null/undefined filter-array entries
instead of crashi...</li>
<li><a
href="https://github.com/ljharb/qs/commit/3a8b94aec19bd664720f6f6b1e66c4a0dfe4b656"><code>3a8b94a</code></a>
[Tests] add regression tests for keys containing percent-encoded bracket
text</li>
<li><a
href="https://github.com/ljharb/qs/commit/96755abd357c0e534dd3442a84a04d08864bfe0d"><code>96755ab</code></a>
[readme] fix grammar</li>
<li><a
href="https://github.com/ljharb/qs/commit/a419ce5bbfcdb98a299f1a0bb47ea055baef20e6"><code>a419ce5</code></a>
[Fix] <code>parse</code>: handle nested bracket groups and add
regression tests</li>
<li><a
href="https://github.com/ljharb/qs/commit/3f5e1c528c967d915096787efbffa73cf6044170"><code>3f5e1c5</code></a>
v6.15.1</li>
<li>Additional commits viewable in <a
href="https://github.com/ljharb/qs/compare/v6.15.0...v6.15.2">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=qs&package-manager=npm_and_yarn&previous-version=6.15.0&new-version=6.15.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/microsoft/teams.ts/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
## Summary
- Removed the old in-repo `@microsoft/teams.cli` package and templates.
Bye bye duplicate CLI.
- Updated sample READMEs to point folks at the official
`@microsoft/teams.cli` package instead.
- Cleaned the lockfile so it no longer tracks the local CLI workspace.

## Test plan
- `npm run build:essential`
- Checked there are no old ATK setup references left in sample docs
…round (#593)

## Summary

- **Deprecate `DevtoolsPlugin`** in `@microsoft/teams.dev`:
`@deprecated` JSDoc on the class, plus a runtime `log.warn(...)` at
`onInit` time so existing users see the deprecation as soon as they
start their bot.
- **Add anonymous-mode startup warning** in `HttpServer.initialize()`
when no `CLIENT_ID` / `CLIENT_SECRET` / `TENANT_ID` is configured, so
customers know their bot accepts unauthenticated requests on
`/api/messages`. 2 new unit tests.
- **Remove `DevtoolsPlugin`** from the 11 example bots (`echo`, `a2a`,
`cards`, `dialogs`, `lights`, `message-extensions`, `quoting`, `tab`,
`targeted-messages`, `threading`, `botbuilder`). The
`@microsoft/teams.dev` dependency is dropped from their `package.json`
as well.
- **Mirror the removal in the CLI templates**
(`packages/cli/templates/typescript/{echo,tab,graph}`) so
newly-scaffolded agents stay in sync with the example bots.
- **README banner** on `@microsoft/teams.dev` pointing at Microsoft 365
Agents Playground.
- `.gitignore`: add `**/devTools/` so the Playground CLI's local log
directory cannot accidentally get committed.

## Why

DevTools is being replaced by Microsoft 365 Agents Playground. The
replacement is a standalone CLI tool, not a package; customers install
it separately and run it alongside their bot. For the grace-period
release, `DevtoolsPlugin` keeps working but loudly signals its
deprecation.

The deprecation message wording is stable across SDKs and stays
version-agnostic per team convention ("a later version", not a specific
version number).

## Note for the CI verification check

skip-test-verification

The CLI templates and example bots are usually kept in sync by the
verification check, but `examples/graph` was already DevtoolsPlugin-free
on main while `packages/cli/templates/typescript/graph` still referenced
it. This PR aligns the template with the (already correct) example, so
the bidirectional-change check sees a one-sided diff. The other two
pairs (echo, tab) have matching changes on both sides.

## Test plan

- [x] `npx turbo build` across all packages and examples (green)
- [x] `npx jest` in `packages/apps` (270/270 passing, including 2 new
tests for the anonymous warning)
- [x] `npx turbo lint` (clean)
- [x] Started an example bot locally and confirmed the deprecation
warning fires
- [x] Captured the anonymous-mode startup warning in the bot console
- [x] `npx turbo build --filter=@microsoft/teams.cli` after template
updates (green)
- [ ] Reviewer to spot-check example bots compile and run without
DevTools

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## Summary

The `ActivityContext` constructor calls `Object.assign(this, rest)` to
copy the public options onto the instance. Because `ActivityContext`
declares `[key: string]: any` to support plugin-supplied extra context,
callers can pass arbitrary properties through. If any of those property
names happened to match a method defined on the prototype (`send`,
`reply`, `quote`, `signin`, `signout`, `next`, `toInterface`), the
spread would shadow the method with whatever value the caller supplied,
leaving the context with a broken or removed behavior for that name.

This change filters `rest` against a derived set of method names derived
from the prototype chain at module load and drops any colliding key
before the assign. Legitimate extra context properties still flow
through unchanged.

## Test plan

- [x] New unit tests in `activity.test.ts` cover: drop of shadowing
properties, preservation of non-colliding extra properties, and that
`ctx.send()` still routes to the prototype implementation when an extra
property of the same name is supplied
- [x] Full `activity.test.ts` suite passes (28/28)

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Bumps [turbo](https://github.com/vercel/turborepo) from 2.8.11 to
2.9.14.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/vercel/turborepo/releases">turbo's
releases</a>.</em></p>
<blockquote>
<h2>Turborepo v2.9.14</h2>
<blockquote>
<p>[!NOTE]
This release contains important security fixes.</p>
</blockquote>
<h3>High:</h3>
<ul>
<li><a
href="https://github.com/vercel/turborepo/security/advisories/GHSA-5xc8-49mv-x4mm">GHSA-5xc8-49mv-x4mm:
Turborepo VSCode Extension command injection</a></li>
</ul>
<h3>Low:</h3>
<ul>
<li><a
href="https://github.com/vercel/turborepo/security/advisories/GHSA-hcf7-66rw-9f5r">GHSA-hcf7-66rw-9f5r:
Login callback CSRF/session fixation</a></li>
<li><a
href="https://github.com/vercel/turborepo/security/advisories/GHSA-3qcw-2rhx-2726">GHSA-3qcw-2rhx-2726:
Unexpected local code execution during Yarn Berry detection</a></li>
</ul>
<!-- raw HTML omitted -->
<h2>What's Changed</h2>
<h3>Changelog</h3>
<ul>
<li>release(turborepo): 2.9.12 by <a
href="https://github.com/github-actions"><code>@​github-actions</code></a>[bot]
in <a
href="https://redirect.github.com/vercel/turborepo/pull/12774">vercel/turborepo#12774</a></li>
<li>fix: Restore docs mobile menu by <a
href="https://github.com/anthonyshew"><code>@​anthonyshew</code></a> in
<a
href="https://redirect.github.com/vercel/turborepo/pull/12782">vercel/turborepo#12782</a></li>
<li>ci: Use <code>pull_request</code> for PR title linting by <a
href="https://github.com/anthonyshew"><code>@​anthonyshew</code></a> in
<a
href="https://redirect.github.com/vercel/turborepo/pull/12787">vercel/turborepo#12787</a></li>
<li>ci: Scope GitHub Actions caches by branch by <a
href="https://github.com/anthonyshew"><code>@​anthonyshew</code></a> in
<a
href="https://redirect.github.com/vercel/turborepo/pull/12788">vercel/turborepo#12788</a></li>
<li>test: Validate lockfiles without dependency downloads by <a
href="https://github.com/anthonyshew"><code>@​anthonyshew</code></a> in
<a
href="https://redirect.github.com/vercel/turborepo/pull/12789">vercel/turborepo#12789</a></li>
<li>Removed unneeded import form hash creation script in docs by <a
href="https://github.com/dancrumb"><code>@​dancrumb</code></a> in <a
href="https://redirect.github.com/vercel/turborepo/pull/12799">vercel/turborepo#12799</a></li>
<li>fix: Validate auth callback state by <a
href="https://github.com/anthonyshew"><code>@​anthonyshew</code></a> in
<a
href="https://redirect.github.com/vercel/turborepo/pull/12802">vercel/turborepo#12802</a></li>
<li>fix: Harden VS Code extension command execution by <a
href="https://github.com/anthonyshew"><code>@​anthonyshew</code></a> in
<a
href="https://redirect.github.com/vercel/turborepo/pull/12800">vercel/turborepo#12800</a></li>
<li>fix: Avoid project-local Yarn during detection by <a
href="https://github.com/anthonyshew"><code>@​anthonyshew</code></a> in
<a
href="https://redirect.github.com/vercel/turborepo/pull/12801">vercel/turborepo#12801</a></li>
<li>chore: Release 2.9.13 by <a
href="https://github.com/anthonyshew"><code>@​anthonyshew</code></a> in
<a
href="https://redirect.github.com/vercel/turborepo/pull/12803">vercel/turborepo#12803</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/dancrumb"><code>@​dancrumb</code></a>
made their first contribution in <a
href="https://redirect.github.com/vercel/turborepo/pull/12799">vercel/turborepo#12799</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/vercel/turborepo/compare/v2.9.12...v2.9.14">https://github.com/vercel/turborepo/compare/v2.9.12...v2.9.14</a></p>
<h2>Turborepo v2.9.13-canary.1</h2>
<!-- raw HTML omitted -->
<h2>What's Changed</h2>
<h3>Changelog</h3>
<ul>
<li>release(turborepo): 2.9.11-canary.7 by <a
href="https://github.com/github-actions"><code>@​github-actions</code></a>[bot]
in <a
href="https://redirect.github.com/vercel/turborepo/pull/12768">vercel/turborepo#12768</a></li>
<li>fix: Allow <code>$TURBO_EXTENDS$</code> in LSP diagnostics by <a
href="https://github.com/anthonyshew"><code>@​anthonyshew</code></a> in
<a
href="https://redirect.github.com/vercel/turborepo/pull/12770">vercel/turborepo#12770</a></li>
<li>release(turborepo): 2.9.11 by <a
href="https://github.com/github-actions"><code>@​github-actions</code></a>[bot]
in <a
href="https://redirect.github.com/vercel/turborepo/pull/12771">vercel/turborepo#12771</a></li>
<li>fix: Allow transit nodes in LSP diagnostics by <a
href="https://github.com/anthonyshew"><code>@​anthonyshew</code></a> in
<a
href="https://redirect.github.com/vercel/turborepo/pull/12773">vercel/turborepo#12773</a></li>
<li>release(turborepo): 2.9.12 by <a
href="https://github.com/github-actions"><code>@​github-actions</code></a>[bot]
in <a
href="https://redirect.github.com/vercel/turborepo/pull/12774">vercel/turborepo#12774</a></li>
<li>fix: Restore docs mobile menu by <a
href="https://github.com/anthonyshew"><code>@​anthonyshew</code></a> in
<a
href="https://redirect.github.com/vercel/turborepo/pull/12782">vercel/turborepo#12782</a></li>
<li>ci: Use <code>pull_request</code> for PR title linting by <a
href="https://github.com/anthonyshew"><code>@​anthonyshew</code></a> in
<a
href="https://redirect.github.com/vercel/turborepo/pull/12787">vercel/turborepo#12787</a></li>
<li>ci: Scope GitHub Actions caches by branch by <a
href="https://github.com/anthonyshew"><code>@​anthonyshew</code></a> in
<a
href="https://redirect.github.com/vercel/turborepo/pull/12788">vercel/turborepo#12788</a></li>
<li>test: Validate lockfiles without dependency downloads by <a
href="https://github.com/anthonyshew"><code>@​anthonyshew</code></a> in
<a
href="https://redirect.github.com/vercel/turborepo/pull/12789">vercel/turborepo#12789</a></li>
<li>Removed unneeded import form hash creation script in docs by <a
href="https://github.com/dancrumb"><code>@​dancrumb</code></a> in <a
href="https://redirect.github.com/vercel/turborepo/pull/12799">vercel/turborepo#12799</a></li>
<li>fix: Validate auth callback state by <a
href="https://github.com/anthonyshew"><code>@​anthonyshew</code></a> in
<a
href="https://redirect.github.com/vercel/turborepo/pull/12802">vercel/turborepo#12802</a></li>
<li>fix: Harden VS Code extension command execution by <a
href="https://github.com/anthonyshew"><code>@​anthonyshew</code></a> in
<a
href="https://redirect.github.com/vercel/turborepo/pull/12800">vercel/turborepo#12800</a></li>
<li>fix: Avoid project-local Yarn during detection by <a
href="https://github.com/anthonyshew"><code>@​anthonyshew</code></a> in
<a
href="https://redirect.github.com/vercel/turborepo/pull/12801">vercel/turborepo#12801</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/vercel/turborepo/commit/fc62fe0d9c347d1d24f0ed8946284856593ddb93"><code>fc62fe0</code></a>
publish 2.9.14 to registry</li>
<li><a
href="https://github.com/vercel/turborepo/commit/fb8c9aec0f9e83f95783659a5ce9c4478cf62cb9"><code>fb8c9ae</code></a>
chore: Release 2.9.13 (<a
href="https://redirect.github.com/vercel/turborepo/issues/12803">#12803</a>)</li>
<li><a
href="https://github.com/vercel/turborepo/commit/e8e629da4e1fb75231089e91b19be9d327a3e649"><code>e8e629d</code></a>
fix: Avoid project-local Yarn during detection (<a
href="https://redirect.github.com/vercel/turborepo/issues/12801">#12801</a>)</li>
<li><a
href="https://github.com/vercel/turborepo/commit/91c90cbf12f524c5c29b713d6472dd5fcdecb309"><code>91c90cb</code></a>
fix: Harden VS Code extension command execution (<a
href="https://redirect.github.com/vercel/turborepo/issues/12800">#12800</a>)</li>
<li><a
href="https://github.com/vercel/turborepo/commit/84f450894e87da1eed864d51f6f637f26980d560"><code>84f4508</code></a>
fix: Validate auth callback state (<a
href="https://redirect.github.com/vercel/turborepo/issues/12802">#12802</a>)</li>
<li><a
href="https://github.com/vercel/turborepo/commit/1779ad7901384f106236a6e196059e4929745514"><code>1779ad7</code></a>
Removed unneeded import form hash creation script in docs (<a
href="https://redirect.github.com/vercel/turborepo/issues/12799">#12799</a>)</li>
<li><a
href="https://github.com/vercel/turborepo/commit/71f8c90a807ffb9b9876ea8a04f523f473bf5c8d"><code>71f8c90</code></a>
test: Validate lockfiles without dependency downloads (<a
href="https://redirect.github.com/vercel/turborepo/issues/12789">#12789</a>)</li>
<li><a
href="https://github.com/vercel/turborepo/commit/5fcb96024d503127bb0ed760ebe159b7716c52b3"><code>5fcb960</code></a>
ci: Scope GitHub Actions caches by branch (<a
href="https://redirect.github.com/vercel/turborepo/issues/12788">#12788</a>)</li>
<li><a
href="https://github.com/vercel/turborepo/commit/4cf9fabc9a6f6c99fe4e2f2da9f35be631be062a"><code>4cf9fab</code></a>
ci: Use <code>pull_request</code> for PR title linting (<a
href="https://redirect.github.com/vercel/turborepo/issues/12787">#12787</a>)</li>
<li><a
href="https://github.com/vercel/turborepo/commit/859c629bc401f239ac7980a132746ca90478e17c"><code>859c629</code></a>
fix: Restore docs mobile menu (<a
href="https://redirect.github.com/vercel/turborepo/issues/12782">#12782</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/vercel/turborepo/compare/v2.8.11...v2.9.14">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
## Summary

Two narrow tightenings of cross-origin policy in the TS SDK.

## Changes

### 1. `ExpressAdapter.serveStatic` — drop wildcard `cors()` middleware

Tab static content was served with a wildcard
`Access-Control-Allow-Origin` header. Teams loads tab content inside an
iframe, governed by CSP `frame-ancestors`, not by CORS. The wildcard
served no documented use case and risked surprising any future endpoint
mounted under the same path.

Callers that legitimately need cross-origin reads of the served assets
can layer their own CORS middleware at the consuming route.

### 2. `DevtoolsPlugin` WebSocket — require same-origin upgrades

The DevTools WebSocket server previously accepted upgrades from any
origin (the `ws` library's default when no `verifyClient` is provided).
The DevTools UI is always loaded from the same origin as the bot server,
so legitimate clients send an Origin header matching the request Host. A
`verifyClient` callback now rejects upgrades whose Origin does not match
the request Host; absent Origin is also rejected.

## What this does not change

- No public API change. No behavior change for in-app same-origin usage.
- `HttpPlugin` (already marked deprecated in-code) still uses a global
`cors()`; that path will be removed with the plugin.

## Validation

- Full monorepo `npm run build`, `npm run test`, `npm run lint` clean.
- `examples/tab` sample: tab index, JS, and CSS still served with HTTP
200 and no `Access-Control-Allow-Origin` header. Cross-origin probe
returns the asset with no `Access-Control-Allow-*` headers, so browsers
would block cross-origin fetch as intended.
- `examples/echo` with devtools enabled: same-origin WebSocket upgrade
succeeds (101); cross-origin and missing-Origin probes return 401 from
the `ws` library.
## Summary

Lockfile-only bumps via `npm audit fix` (no `--force`). Closes all
high-severity advisories.

**Before**: 20 prod vulns (2 high, 14 moderate, 4 low)
**After**: 13 prod vulns (0 high, 9 moderate, 4 low)

## What got bumped

| Package | From → To | Severity cleared |
|---|---|---|
| axios | 1.13.5 → 1.16.1 | **high** — 15 advisories (SSRF via
`NO_PROXY` bypass, prototype pollution in `validateStatus` /
`parseReviver` / `withXSRFToken` / form-data, CRLF injection in
multipart, null byte injection, unbounded recursion DoS) |
| fast-uri | 3.1.0 → 3.1.2 | **high** |
| ws | 8.19.0 → 8.21.0 | moderate (uninitialized memory disclosure) |
| @azure/msal-node | added 5.2.2 (hoisted; older copies stay under
botbuilder) | moderate (uuid transitive) |
| uuid | 11.1.0 → 11.1.1 | moderate |
| @azure/identity | 4.13.0 → 4.13.1 | moderate |
| express-rate-limit | 8.3.1 → 8.5.2 | moderate (via ip-address) |
| ip-address | 10.1.0 → 10.2.0 | moderate |
| brace-expansion | 5.0.5 → 5.0.6, 2.0.2 → 2.1.1 | moderate |
| browserify-sign | 4.2.5 → 4.2.6 | low (elliptic) |
| picomatch | 2.3.1 → 2.3.2 | — |
| proxy-from-env | 1.1.0 → 2.1.0 | — |

## What's NOT addressed

13 advisories remain, all in the **Bot Framework SDK** transitive chain
via `packages/botbuilder` (which pins `botbuilder@4.23.1`):

- `botbuilder`, `botbuilder-core`, `botframework-connector`,
`botframework-schema`, `botframework-streaming`
- `@azure/core-http`, nested `@azure/msal-node` (under
botbuilder/botframework-connector), `uuid` (transitive)
- `restify` (direct dep of botframework)
- `elliptic`, `crypto-browserify`, `browserify-sign`, `create-ecdh`
(low-severity cryptography chain via botbuilder)

`npm audit fix`'s suggested resolution is `botbuilder@4.11.2`, which is
**older** than our pinned 4.23.1 and would lose features. Declining.
Same shape as teams.py's `jsonpickle` situation — Bot Framework SDK is
archived and pins old transitives.

## Test plan

- [x] `npm run build` — all 33 targets clean
- [x] `npm test` — all 14 targets, 279+ unit tests pass
- [x] **E2E smoke test** — echo bot against `cg-test-bot-py` via canary
ABS:
- Inbound activity received, JWT trust-boundary validated successfully
(also exercises #586 hardening)
  - msal-node token acquisition succeeded
  - Bot replied via axios POST to canary `serviceUrl`
  - Reply visible in Teams client
@corinagum corinagum merged commit e94cc77 into release May 27, 2026
4 checks passed
@corinagum corinagum deleted the prep-release/2.0.12 branch May 27, 2026 23:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants