power-apps-code-app
Use this skill whenever the user works on a Microsoft Power Apps code app project — deploying, pushing, rattaching to a solution, debugging connections, or preparing for ALM. Triggers include any mention of `pac code` commands, `pac code push`, `pac code add-data-source`, `npx power-apps push`, `@microsoft/power-apps`, `@microsoft/power-apps-cli`, `power.config.json`, "code app", "Power Apps Code App", pushing a code app to an environment or a solution, attaching a code app to a Dataverse solution, connection references in a code app, Copilot Studio agent in a code app, Office 365 / SharePoint / Dataverse connectors in a code app, or errors like `Cannot add CanvasApp ... to solution because it does not exist`. Do NOT use for classic canvas apps (.msapp), model-driven apps, Power Pages, or Power Automate flows — only for the newer "code apps" (React/Vite/TypeScript deployed via PAC CLI or npm CLI).
~/.claude/skills/power-apps-code-appPower Apps Code Apps — déploiement et cycle de vie
Contexte et vocabulaire
Une Power Apps Code App est une app web (React/Vite/TypeScript typiquement) déployée dans un environnement Power Platform. Sous le capot elle est stockée dans Dataverse comme une entité canvasapp avec un flag "code app", ce qui explique plusieurs bizarreries héritées du monde canvas classique.
Trois packages npm entrent en jeu — ne pas confondre :
| Package | Rôle | Fournit le binaire power-apps |
|---|---|---|
@microsoft/power-apps | Client library (SDK runtime) | Non |
@microsoft/power-apps-cli | CLI npm (power-apps command) | Oui |
@microsoft/power-apps-vite | Plugin Vite de build | Non |
Deux CLI coexistent, avec les mêmes capacités à peu près :
- PAC CLI (
pac code ...) — historique, .NET, à terme déprécié - npm CLI (
npx power-apps ...) — le remplaçant recommandé par Microsoft
Les deux tapent la même API Dataverse en dessous, donc les mêmes bugs serveur existent des deux côtés.
Étape 1 — Premier déploiement d'une code app dans une solution
Ne fais pas confiance aux flags --solutionName / -s pour rattacher : ils sont parsés mais le rattachement Dataverse n'est pas effectué côté serveur (bug en preview confirmé). Procédure qui marche aujourd'hui :
1.1 Pré-requis
pac auth create --environment <ENVIRONMENT_ID>
pac env select --environment <ENVIRONMENT_ID>
pac env who # confirme l'env actif
La solution cible doit déjà exister dans l'environnement et être unmanaged. Vérifier avec :
pac solution list
Noter le Unique Name (pas le Friendly Name) — c'est ce qu'attendent les CLI.
1.2 Vérifier les connexions nécessaires
Pour chaque connecteur qu'utilise l'app (Office 365 Users, SharePoint, Copilot Studio, Dataverse, etc.) :
pac connection list
Chaque connexion utile doit être en statut Connected. Si elle est en Error, la réparer d'abord (cf. section Troubleshooting connexions) — sinon pac code add-data-source renverra des 404 trompeurs sur une URL de connectivity (le 404 ne dit pas "connexion cassée", il dit "endpoint not found" alors que la vraie cause est la connexion en erreur).
1.3 Initialisation et ajout des data sources
pac code init --displayname "mon_app"
pac code add-data-source -a "shared_office365users" -c <connectionId>
# etc. pour chaque connecteur
1.4 Premier push
npm run build
npx power-apps push
# ou, équivalent: pac code push
Le push réussit et te donne une URL play. Note le GUID de l'app dans l'URL (.../app/<appId>?...).
1.5 Rattacher l'app à la solution (l'étape que les CLI ratent)
Voie portail (la plus fiable) :
- make.powerapps.com → environnement cible
- Solutions → ta solution
- + Ajouter existant → App → Application canevas
- Sélectionner l'app dans le picker → Ajouter
Le picker résout correctement l'App ID (utilisé côté PowerApps) vers le canvasappid (clé primaire Dataverse), qui sont différents. C'est pour ça que la voie CLI directe échoue :
# ÉCHOUE avec "Cannot add CanvasApp ... because it does not exist"
pac solution add-solution-component \
--solutionUniqueName <solutionUniqueName> \
--component <appId-from-url> \
--componentType 300
Le --component attend le canvasappid Dataverse, que seule une requête OData (/api/data/v9.2/canvasapps?$filter=...) peut fournir — trop lourd pour un rattachement unique, d'où le portail.
Étape 2 — Pushes successifs (workflow quotidien)
Une fois l'app rattachée à la solution, la liaison persiste côté Dataverse. Plus besoin de flag ni de prompt :
npm run build
npx power-apps push
L'app est mise à jour dans la solution, version incrémentée, tout bon. Ne pas retenter --solutionName — ça ne casse rien mais ça n'apporte rien non plus.
Troubleshooting connexions
Symptôme : pac code add-data-source renvoie HTTP 404
Cause la plus fréquente : la connexion référencée est en statut Error dans pac connection list. Le 404 n'est pas descriptif.
Fix :
- make.powerapps.com → bon environnement → Plus → Connexions
- Trouver la connexion avec l'icône d'avertissement
- Cliquer Corriger la connexion et ré-authentifier. Ou supprimer et recréer.
pac connection listdoit maintenant afficher Connected pour cette ligne.- Relancer
pac code add-data-source.
Symptôme : plusieurs connexions en Error simultanément
Très probablement des tokens OAuth expirés suite à changement de mot de passe / MFA / inactivité prolongée. Fix groupé via le portail (réparation une par une).
Symptôme : bon env mais pas les bonnes connexions
Vérifier qu'on est bien dans l'environnement attendu :
pac env who
pac env list
pac env select --environment <correctEnvId>
Bugs connus et workarounds (au 2026-04)
1. pac code push --solutionName / npx power-apps push -s parsés mais non effectifs
Symptôme : le push réussit, l'app est dans l'environnement, mais absente des composants de la solution ciblée. Workaround : rattachement manuel via portail (cf. Étape 1.5), une seule fois.
2. Prompts interactifs @clack/prompts invisibles sur macOS
Symptôme : npx power-apps push affiche uniquement des ◇ et des │ sans texte, puis pushe directement sans demander la solution. Terminal.app et terminal intégré VS Code touchés identiquement. Ne touche pas Windows.
Workaround : passer les valeurs par flag plutôt qu'attendre le prompt — ou ignorer, puisque le rattachement est de toute façon à faire via portail.
3. --help de npx power-apps push incohérent
L'exemple affiche --solution-name mais le flag reconnu est -s / --solution-id (alors que ce dernier accepte aussi un nom unique, pas seulement un GUID). Utiliser -s <uniqueName>.
4. App ID (URL play) ≠ canvasappid (Dataverse PK)
Symptôme : pac solution add-solution-component --component <appId> renvoie Cannot add CanvasApp with id (…) to solution because it does not exist.
Cause : l'App ID qu'on voit dans l'URL /play/e/<env>/app/<appId> n'est pas la clé primaire Dataverse.
Workaround : utiliser le picker "Ajouter existant" du portail qui fait la résolution.
5. Versions des packages à bien distinguer
- Le binaire
power-appsvient de@microsoft/power-apps-cli(actuellementlatest = 0.10.0). - Le SDK
@microsoft/power-appsest surlatest = 1.1.1. - Mettre à jour le SDK n'update pas le CLI. Pour upgrader le CLI :
npm install @microsoft/power-apps-cli@latest
6. Cache npx tenace
Si npx power-apps --version renvoie une vieille version malgré un upgrade :
rm -rf ~/.npm/_npx
npx --yes -p @microsoft/power-apps-cli@latest power-apps --version
Note la syntaxe -p <package> qui force le package source quand le nom de commande diffère du nom de package.
7. Code apps enabled sur l'environnement
Si un premier pac code push renvoie une 500 ou un message auth bizarre, vérifier dans Power Platform admin center → ton env → Settings → Product → Features qu'Enable code apps est activé.
ALM et connection references
Pour qu'une code app soit exportable/ré-importable proprement (CI/CD, dev→test→prod), les connexions ne doivent pas être en dur par connection ID — elles doivent passer par une connection reference stockée dans la solution.
Ajouter un connecteur avec connection reference
pac code add-data-source \
-a "shared_microsoftcopilotstudio" \
-cr <connectionReferenceLogicalName> \
-s <solutionId>
-cr: nom logique de la connection reference (ex.pub_copilotStudioConn)-s: GUID de la solution Dataverse
Créer la connection reference
Soit dans le portail (Solution → Nouveau → Plus → Connexion → Référence de connexion), soit via une solution unpacked. La connection reference pointe vers un connecteur (API ID) et sera résolue vers une vraie connexion au moment de l'import dans chaque environnement cible (via settings-file JSON).
Vérification
pac code list-connection-references --solutionId <solutionGuid>
Pour les data sources Dataverse
Pas besoin de connection reference — Dataverse est natif, l'app est liée par environmentId dans power.config.json. Ce sont les connecteurs tiers (Office 365, SharePoint, Copilot Studio, SQL, etc.) qui ont besoin de connection references pour être portables.
Types générés vs runtime réel — piège transverse
Règle d'or : les services TypeScript générés par PAC CLI dans src/generated/ peuvent mentir sur la forme du runtime. Plusieurs cas observés :
- Type de retour annoncé
IOperationResult<void>alors queresult.datacontient un objet structuré. - Signature générée en paramètres positionnels alors que MS Learn documente un objet (
{ message, notificationUrl, agentName }). - Casing des propriétés qui varie selon le connecteur (
conversationIdvsConversationId). - Propriétés non documentées (ex.
isExpectingInput).
Workflow recommandé pour tout nouveau connecteur tiers :
- POC one-shot avant tout code de prod :
// src/pages/poc-<connector>.tsx (dev-only route) const result = await SomeGeneratedService.SomeAction(...) return <pre>{JSON.stringify(result, null, 2)}</pre> - Observer la forme réelle : shape de
data, casing, champs non documentés, latence. - Définir un type runtime dans
src/types/:export interface SomeActionResponse { fieldA?: string // défensif — peut être absent FieldA?: string // casing observé dans une variante unknownField?: boolean // observé mais non documenté } - Dans le hook, caster :
result.data as unknown as SomeActionResponse. - Extraction défensive avec optional chaining triple si le casing est incertain :
const id = data?.conversationId ?? data?.ConversationId ?? data?.conversationID
Règle d'or associée : le SDK @microsoft/power-apps ne throw jamais. Il retourne { success: false, error }. Toujours checker result.success avant d'accéder à result.data — un try/catch autour d'un appel SDK ne masquera pas les échecs logiques.
Connecteur Copilot Studio dans une Code App
Pour brancher un agent Copilot Studio publié à une code app :
Setup
- Agent : créer l'agent dans Copilot Studio, publier, copier le nom exact depuis l'URL Channels → Web app (ex.
gg_Agentdetest). Sensible à la casse, préfixe éditeur inclus. - Connexion : dans le portail Power Apps, créer/vérifier une connexion
shared_microsoftcopilotstudioen statut Connected. Si Error, réparer avant toutadd-data-source. - Env var : stocker le nom de l'agent dans
.env.local(ignoré via*.local) :VITE_COPILOT_AGENT_NAME=<publisher_agentName> - Data source :
npx power-apps add-data-source -a "shared_microsoftcopilotstudio" -c <connectionId> # ou pac code add-data-source ...
Pièges spécifiques Copilot Studio
| Piège | Réalité | Mitigation |
|---|---|---|
| Trois actions disponibles | ExecuteCopilot (fire-and-forget, pas de réponse) et ExecuteCopilotAsync (peut 502) | Utiliser ExecuteCopilotAsyncV2 uniquement |
| Signature doc MS Learn | Objet { message, notificationUrl, agentName } | La signature générée est positionnelle : (Copilot, body, x_ms_conversation_id?, environmentId?) |
| Type de retour généré | IOperationResult<void> | Runtime réel : { responses: string[], conversationId: string, completed: boolean, isExpectingInput: boolean } |
| Nom de la classe générée | Pas forcément CopilotStudioService | Observé : MicrosoftCopilotStudioService |
notificationUrl requis | Champ string obligatoire même en mode sync | Valeur placeholder : "https://notificationurlplaceholder" |
Casing conversationId | Parfois ConversationId, parfois conversationID | Extraction triple optional chaining |
| Pas de streaming | Latence ~1-5s visible | Typing indicator pendant status === "sending" |
| Payload utilisateur | Un seul champ string (message) | JSON.stringify un objet { userMessage, context, conversation } et parser côté agent |
Pattern d'appel minimal
const result = await MicrosoftCopilotStudioService.ExecuteCopilotAsyncV2(
import.meta.env.VITE_COPILOT_AGENT_NAME,
{ message: JSON.stringify(payload), notificationUrl: "https://notificationurlplaceholder" },
previousConversationId ?? undefined,
)
if (!result.success) throw result.error
const data = result.data as unknown as CopilotRuntimeResponse
const convId = data?.conversationId ?? data?.ConversationId ?? data?.conversationID
const reply = data?.responses?.[data.responses.length - 1] ?? data?.lastResponse ?? ""
Contextualisation par injection JSON
Pour que l'agent contextualise ses réponses avec des filtres de l'app (ex. entreprise sélectionnée), wrapper le message utilisateur dans un payload JSON avec un champ context, et faire parser ce JSON côté topic de l'agent (action "Parse JSON" sur la variable Activity.Text). Exposer ce payload à l'utilisateur via un panneau repliable "Contexte envoyé à l'agent" pour la transparence.
Anti-patterns à signaler
- ❌ Éditer les fichiers sous
src/generated/: réécrits à chaquepac code add-data-source. - ❌ Committer
power.config.jsonavec unenvironmentIdde production partagé : préférer plusieurs fichiers de config ou des variables d'env. - ❌ Pousser des connexions avec des IDs en dur si l'app doit être transportable → utiliser connection references.
- ❌ Relancer 10 fois
pac code push --solutionNameen espérant que le rattachement finisse par fonctionner : il ne fonctionnera pas tant que le bug serveur n'est pas résolu. - ❌ Faire confiance au type de retour
IOperationResult<void>d'un service généré sans POC préalable : plusieurs actions renvoient en réalité des objets structurés. - ❌ Utiliser
try/catchautour d'un appel SDK Power Apps en pensant gérer les erreurs : le SDK retourne{ success: false, error }, il ne throw pas. Toujours checkerresult.success. - ❌ Utiliser l'action
ExecuteCopilot(fire-and-forget) en espérant une réponse : elle ne retourne rien. SeulExecuteCopilotAsyncV2renvoie le contenu.
Références
- Doc officielle : https://learn.microsoft.com/en-us/power-apps/developer/code-apps/
- PAC CLI
pac code: https://learn.microsoft.com/en-us/power-platform/developer/cli/reference/code - PAC CLI
pac solution: https://learn.microsoft.com/en-us/power-platform/developer/cli/reference/solution - npm CLI quickstart : https://learn.microsoft.com/en-us/power-apps/developer/code-apps/how-to/npm-quickstart
- Issues repo : https://github.com/microsoft/PowerAppsCodeApps/issues
