refactor(apps): Move from file-based mixins to real classes#633
Merged
Conversation
Convert App-bound free functions into dedicated collaborator classes and smart context objects, mirroring the teams.py structure: - Add PluginManager (app.plugins.ts) owning plugin registry, DI/event injection, and init/start/stop lifecycle - Add FunctionContext class (contexts/function.ts) owning send() and conversation-id resolution; refactor getConversationIdResolver to take api instead of app - Inline on/message/use/event/function/tab into App; delete app.routing.ts and app.embed.ts - Remove the as TokenExchangeInvokeResponse cast in app.oauth.ts - Fully encapsulate App plugin state (remove public plugins getter) Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
corinagum
approved these changes
Jun 30, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
Refactors @microsoft/teams.apps internals away from this: App-bound free functions into dedicated collaborator classes (PluginManager, EventManager, ActivityProcessor, OauthHandlers) and a “smart” FunctionContext, aiming to improve encapsulation and reduce App surface area without changing end-user behavior.
Changes:
- Introduces collaborator classes for plugins/events/activity processing/oauth and rewires
Appto delegate to them. - Adds
FunctionContextclass and updates conversation-id resolution helper to acceptApiClientdirectly. - Removes legacy mixin-style files (
app.routing.ts,app.embed.ts) and updates/expands tests accordingly.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/apps/src/utils/function-context.ts | Refactors resolver helper to take ApiClient instead of App. |
| packages/apps/src/utils/function-context.spec.ts | Updates tests to pass app.api into resolver helper. |
| packages/apps/src/contexts/function.ts | Introduces FunctionContext class implementing function send/conversation resolution. |
| packages/apps/src/app.ts | Inlines routing/tab/function APIs as real methods; wires new collaborators; narrows tokenManager visibility. |
| packages/apps/src/app.routing.ts | Deleted legacy routing mixin free functions. |
| packages/apps/src/app.process.ts | Replaces $process free function with ActivityProcessor class. |
| packages/apps/src/app.process.spec.ts | Adds coverage for lifecycle events emitted during processing. |
| packages/apps/src/app.plugins.ts | Replaces plugin helpers/mixins with PluginManager class and handler hooks. |
| packages/apps/src/app.oauth.ts | Replaces oauth mixins with OauthHandlers collaborator; removes cast via typed body. |
| packages/apps/src/app.events.ts | Replaces event mixins with EventManager collaborator. |
| packages/apps/src/app.embed.ts | Deleted legacy embed/function/tab mixin free functions. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
lilyydu
approved these changes
Jun 30, 2026
heyitsaamir
added a commit
that referenced
this pull request
Jul 10, 2026
Resolve conflicts from main's class refactor (PR #633): - Add flattened methods to ConversationClient (createActivity, updateActivity, getMemberById) - Add flattened methods to UserClient (getToken, exchangeToken, etc.) - Keep our agentic auth additions (AuthProvider, RequestOptions, cloud) Co-authored-by: Copilot App <[email protected]>
Merged
lilyydu
added a commit
that referenced
this pull request
Jul 16, 2026
## Release v2.0.14
Prepares the stable **2.0.14** release by merging `main` into `release`
and setting `version.json` to the stable version (removing the
`-preview.{height}` suffix).
- Previous release: `2.0.13` (published 2026-06-15)
- Only functional diff vs `main` is `version.json`:
`2.0.14-preview.{height}` → `2.0.14`
## What's in this release
### 🚀 Features
* Flatten client method chains to reduce call hops by @lilyydu in
#634
* Support resetting response streams and streaming error handling by
@lilyydu in #635
* Add `extendedMarkdown` text format value by @singhk97 in
#615
### 🐛 Fixes
* Set `replyToId` for all streaming activities by @lilyydu in
#646
* Use `artifactName` for pipelineArtifact inputs in publish pipeline by
@corinagum in #625
### ♻️ Refactors
* Move `apps` from file-based mixins to real classes by @heyitsaamir in
#633
* Split up Outbound and Inbound Activities by @heyitsaamir in
#639
* Remove `ExperimentalTeamsQuotedReplies` markers by @corinagum in
#621
### 🧪 Tests
* Add integration tests for Teams TypeScript SDK by @corinagum in
#622
### 📚 Docs & Examples
* Migrate examples to the flattened conversation API by @lilyydu in
#637
* Note npm CFS proxy for Microsoft-managed devices by @corinagum in
#638
* Update integration test runbook link to ADO wiki by @corinagum in
#624
### 🔧 Chores & Dependencies
* Bump version to 2.0.14-preview and fix pipeline release job by
@corinagum in #620
* Bump hono from 4.12.21 to 4.12.25 by @dependabot in
#623
* Bump react-router from 7.15.0 to 7.15.1 by @dependabot in
#619
* Bump vite from 6.4.2 to 6.4.3 by @dependabot in
#617
**Full Changelog**:
v2.0.13...prep-release/2.0.14
### After merge
1. Trigger the [release
pipeline](https://dev.azure.com/DomoreexpGithub/Github_Pipelines/_build?definitionId=52&_a=summary)
on `release` with **Public** publish type
2. Bump `main` → `2.0.15-preview.{height}`
3. Create the `v2.0.14` git tag + GitHub Release
Co-authored-by: Copilot <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Internal refactor of
@microsoft/teams.appsthat convertsthis: App-bound free functions into dedicated collaborator classes and "smart" context objects, mirroring the structure of the Python SDK (teams.py). No intended change to end-user behavior — this is structural cleanup.Why the previous approach was bad
The old design implemented a lot of
App's behavior as standalone free functions inapp.routing.ts/app.embed.tsthat were bound onto the class withthis: Appand assigned likeon = on; message = message; func = func; tab = tab;. That had several problems:Appasthis, so they could reach into any field onApp(the DI container, event manager, token manager, server, plugin array, etc.). Dependencies were implicit and untracked — you couldn't tell what a function actually needed without reading its whole body, and nothing stopped it from depending on more over time.Appwas a god object. Plugin lifecycle/registration/injection, activity processing, oauth handling, and function/tab wiring were all smeared acrossAppplus a grab-bag of free-function files, instead of living in cohesive units. This made the class hard to read and reason about, and changes in one concern risked touching unrelated ones.Changes
PluginManager(app.plugins.ts) — owns the plugin registry, duplicate-name check, container double-registration, dependency/event injection, andonInit/onStart/onStoplifecycle.Appdelegatesplugin()/getPlugin()to it. Thepluginsgetter returns the live array soEventManager/ActivityProcessorobserve plugins added after construction.FunctionContextclass (contexts/function.ts) — ownssend()and conversation-id resolution, replacing the inline closures.getConversationIdResolvernow takesapiinstead ofapp.on/message/use/event/function/tabintoAppas proper methods; deletedapp.routing.tsandapp.embed.ts.app.oauth.ts— removed theas TokenExchangeInvokeResponsecast in favor of a typedconst body.Appplugin state (removed the publicpluginsgetter;getPlugin(name)remains the read path).Verification
tscclean, eslint cleanReviewer note
tokenManagervisibility was narrowed frompublic readonlytoprotected readonly