Skip to main content

state

Store and query a Microsoft Managed App's built-in state and file attachments with `ms project state` CLI schema commands and generated TypeScript clients. First, with the user signed in to the CLI, run `ms feature status --name state --json`; if `feature.enabled` is not `true`, recommend an alternative connector or data source.

ソース情報

リポジトリ
microsoft/managed-apps
ソースの最終更新活動
2026年10月10日 00:24
検出された SKILL.md の言語
英語
スター
32
フォーク
9

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
state
description
Store and query a Microsoft Managed App's built-in state and file attachments with `ms project state` CLI schema commands and generated TypeScript clients. First, with the user signed in to the CLI, run `ms feature status --name state --json`; if `feature.enabled` is not `true`, recommend an alternative connector or data source.
user-invocable
true
allowed-tools
Read, Edit, Write, Grep, Glob, Bash, AskUserQuestion
model
sonnet
**📋 Shared Instructions: [shared-instructions.md](${CLAUDE_PLUGIN_ROOT}/shared/shared-instructions.md)** — Cross-cutting concerns. # Managed Apps State with CLI schema + generated client Every Microsoft Managed App can use built-in app state when the `state` feature is enabled for the current CLI/environment: a NoSQL store the app calls directly (no middle-tier function, connector, or SDK; the host attaches auth). Records are grouped into collections by an item type name; the server assigns each record an `itemId`. For schema-backed state, **do not edit schema JSON by hand.** Use `ms project state ...` to change the schema, run `ms project state generate-code`, then call the generated TypeScript services from app code. ## Mandatory feature gate Before using any guidance in this skill, it is recommended that the user is signed in to the CLI. Run `ms auth status`, and if it reports no signed-in account, ask the user to run `ms auth login`. `ms feature status` never prompts for sign-in, and features that are on by default for the user's organization only apply once they are signed in, so a signed-out check can report `state` as disabled even when it is available to them. Then run: ```bash ms feature status --name state --json ``` Continue only when the output has `"success": true` and `feature.enabled` is `true`. Read the JSON rather than the human-readable output, which lists several settings that can each say "enabled". If the command fails (non-zero exit or `"success": false`), the feature is not found, or `feature.enabled` is `false`, stop and do **not** run any `ms project state ...` command. When state is not enabled, recommend an alternative data-source path based on the user's need: - Durable relational/business data: use `/add-dataverse`. - SharePoint lists or document-backed collaboration data: use `/add-sharepoint`. - Workbook-backed tabular data: use `/add-excel`. - Mail, calendar, user profile, Teams, Azure DevOps, OneDrive, Copilot Studio, or Work IQ scenarios: use the matching `/add-*` skill. - Anything else: use `/add-data-source` to discover and bind the appropriate connector. Do not suggest manual schema edits or custom proxy workarounds as a substitute for the disabled feature. ## ⚠️ Local testing requires local gateway mode Generated state services require the Managed Apps local gateway path during local development. Before testing data behavior locally, make sure the app has `@microsoft/managed-apps-vite-plugin` 0.4.2 or later (the version that added `devMode: 'localGateway'`; older versions won't start the local gateway), then opt the app into local gateway mode. Check the installed version first, for example with `npm ls @microsoft/managed-apps-vite-plugin` (or read `version` in `node_modules/@microsoft/managed-apps-vite-plugin/package.json`). If it is 0.4.2 or later, skip the install. If it is missing or older, install the latest with the app's package manager: ```bash npm install -D @microsoft/managed-apps-vite-plugin@latest # or: bun add -D @microsoft/managed-apps-vite-plugin@latest # or: pnpm add -D @microsoft/managed-apps-vite-plugin@latest # or: yarn add -D @microsoft/managed-apps-vite-plugin@latest ``` Then update the app's `vite.config.ts` so the `managedApps()` plugin call enables the local gateway, preserving any existing options: ```ts managedApps({ ...existingOptions, devMode: 'localGateway', }) ``` Now run local dev normally: ```bash ms app dev ``` Do not change the app architecture just to work around local data failures (no middle-tier functions, proxies, or CORS/auth workarounds). Fix the Vite plugin/local gateway setup instead. ## Contract | Surface | Use | Don't use | | --- | --- | --- | | Feature gate | `ms feature status --name state --json` (`feature.enabled`), with the user signed in, before any state work | assuming the feature is available | | Schema edits | `ms project state add`, `alter`, `remove`, `set-setting` | manual edits to `state/schema.json`, `ms.schema.json`, or another configured schema file | | Code generation | `ms project state generate-code` | handwritten model/service/validator files in the generated output folder | | App data access | generated services, models, validators, and typed query helpers | treating direct state requests as the default when codegen covers the scenario | | File attachments | direct upload to `/.ms/state/attachments`, then save the returned URL through a generated service | storing file bytes inside items | | Testing data behavior | Vite plugin 0.4.2+ + `managedApps({ devMode: 'localGateway' })` + `ms app dev`; Preview for pre-deploy validation | local dev without local gateway mode | The generated services own request shapes, ETags, typed filters, paging, validation hooks, per-user scope behavior, and service route details. App code should compose those services with UI/business logic instead of duplicating transport behavior. ## Workflow 1. Make sure the user is signed in (`ms auth status`; ask them to run `ms auth login` if not), then run `ms feature status --name state --json`. Stop and recommend a connector alternative unless `feature.enabled` is `true`. 2. Find the app root (`ms.config.json`) and the configured schema path. 3. Inspect existing state schema/settings with `ms project state list-schema` and `ms project state list-settings`. 4. For each new collection, decide up front whether records are per-user (see below). 5. Make schema changes only with `ms project state ...` commands. 6. Run `ms project state generate-code` after every successful schema change. 7. Import and use the generated TypeScript services from app code. 8. Configure local gateway mode before local data testing. 9. Build/typecheck and verify that generated services are used for behavior covered by codegen. ## Schema setup Find the app root (`ms.config.json`) and the configured schema path. Prefer `state.schemaPath`; older apps may use `data.schemaPath` or legacy `db.schemaPath`. ```json { "state": { "schemaPath": "state/schema.json", "enabled": true } } ``` If no schema path exists yet, start by adding the first collection with the CLI. It writes `state.schemaPath: "state/schema.json"`, creates the schema file, and sets `enabled: true` unless the config already sets `enabled`; don't ask the user to hand-configure schema wiring first. The app serves no state while `enabled` is `false`, so confirm with the user before changing an explicit `false`. New schemas take the machine's locale (or `en-US`); match the app's users with `ms project state set-setting --locale <tag>`. Inspect the current schema: ```bash ms project state list-schema ms project state list-settings ``` ## CLI schema commands ### Add a collection ```bash ms project state add --collection task ``` ### Add properties ```bash ms project state add --collection task --property name --type string --required true --max-length 200 --index true --index-ignore-case true ms project state add --collection task --property done --type boolean ms project state add --collection task --property dueDate --type datetime --index true ms project state add --collection task --property attachment --type binary --kind binary ``` - **Types:** `string`, `number`, `integer`, `boolean`, `datetime`, `guid`, `binary`. - **Boolean flags take values:** `--required true`, `--index false`, etc. They are not bare switches. - **Indexes:** at most four custom indexed properties per collection, top-level scalars only. Only indexed properties (plus `itemId`, `name`, `createdTime`, `modifiedTime`) can be filtered or sorted. - **Name property:** prefer a human-readable `name` property for each item (put a single-string item's text there). It is writable, indexed, sortable/filterable, and generated services treat it as the display/title field. ### Alter a property ```bash ms project state alter --collection task --property name --max-length 200 ms project state alter --collection task --property done --required false ms project state alter --collection task --property name --max-length "" ``` Only pass the flags you intend to change. Empty string clears a type-specific constraint where the CLI supports clearing. Indexes are add-only. Removing an index or changing its options (including the platform index on `name`) is rejected even before the first deploy, so choose `--index-ignore-case` and `--index-ignore-accents` when you add the property. Adding an index to an already-deployed property is allowed, but validate it in Preview first. ### Remove a property ```bash ms project state remove --collection task --property obsoleteField ``` Use `--force` only when non-interactive automation is necessary and the user already approved the removal. Stored values are not deleted. Collection removal is intentionally rejected; do not work around it by editing the schema file. ### Change schema settings Set exactly one setting per command: ```bash ms project state set-setting --locale en-US ms project state set-setting --validation true ms project state set-setting --validation false ``` `--validation false` keeps declared indexes active but makes writes index-only/unvalidated. ### Per-user collections Make a collection per-user when a record belongs to one person (drafts, preferences, personal notes); skip it for catalogs, reference data, and anything collaborative. **Decide before it holds records:** ownership is immutable and can't be added to a collection that has data. The CLI has no ownership flag, so this is the one schema edit allowed by hand, and only after the user agrees: add `"x-ms-ownership": "perUser"` to the collection's root object (not a property), change nothing else, and regenerate. Generated services then take a `scope` option: `private` writes/reads only the caller's records, `shared` writes/reads records visible to all users, and omitting it writes private and reads both. Pass it explicitly on writes. The owner always comes from the caller's token; reads include a platform-managed `@ms.scope` that you must not send back. ## Generate the typed client Run this after every successful schema change: ```bash ms project state generate-code ``` For automation or precise diagnostics: ```bash ms project state generate-code --json ``` Output is written to `generated-typescript/` beside the configured schema file. For `state.schemaPath: "state/schema.json"`, output is `state/generated-typescript/`. Treat that folder as generator-owned: - first generation accepts a missing or empty directory; - replacement requires the ownership manifest and no untracked handwritten files; - move handwritten wrappers/hooks outside the generated directory; - never edit generated models, services, validators, query helpers, or manifests by hand. ## App code Import from the generated barrel. Each collection gets a service class with static methods, read/write types, and a validator: `task` gives `TaskService`, `TaskRead`, `TaskWrite`, and `validateTask(item)`, which returns `ValidationError[]` for form errors (services validate on write). ```ts import { TaskService, type TaskRead, type TaskWrite } from '../state/generated-typescript'; export async function createTask(input: TaskWrite): Promise<TaskRead> { // With validation on, invalid input fails with error.kind === 'validation'. const result = await TaskService.create(input); if (!result.success) { throw new Error(`Could not create the task: ${result.error.message}`); } return result.data; } export async function listUpcomingTasks(): Promise<TaskRead[]> { const q = TaskService.query; const result = await TaskService.getAll({ filter: q.ge('dueDate', new Date().toISOString()), orderBy: q.orderBy('dueDate', 'asc'), maxItems: 50, }); if (!result.success) { throw new Error(`Could not load tasks: ${result.error.message}`); } return result.data; } ``` Direct requests to `/.ms/state/{collection}/items[/{itemId}]` are acceptable only with a deliberate reason to bypass the generated services. They follow the same contract: send `@odata.etag` verbatim as `If-Match`, follow `@odata.nextLink` to page (`$skip` is rejected), sort with `$orderby=<field> asc|desc`, and quote string and date literals in `$filter` (URL-encode both). ## Generated-service behavior - **Results, not exceptions:** service calls return `{ success: true, data }` or `{ success: false, error }` (`error.kind`, `message`, `status`, `validationErrors`). Check `success` before using `data`. - **Create/update validation:** generated validators enforce the declared schema when validation is enabled. `update` is a full-document PUT/upsert, not a partial patch. - **Edit with concurrency:** generated edit helpers read the item, shallow-merge callback changes, validate, and send the exact quoted ETag in `If-Match`. Only `412` is retried. - **Delete is idempotent:** deleting a missing item succeeds, so retries are safe. - **Server-owned fields:** `itemId`, `createdTime`, `modifiedTime`, and `@odata.etag` are read-only. Do not send them in write models. - **Queries:** `getAll` follows every page (cap it with `maxItems`); `getPage` returns one page and a `nextLink` (`top` sets the page size). Build `filter` and `orderBy` with the typed `query` builder (`eq`, `ne`, `gt`, `lt`, `le`, `ge`, `and`, `or`, `orderBy(field, 'asc' | 'desc')`); both accept only indexed fields. `rawFilter(expr)` is the explicit escape hatch for raw OData filters. - **Per-user data:** for `x-ms-ownership: "perUser"`, generated services expose scope-aware reads and writes. Do not send scope to non-per-user collections; the service rejects it with `400`. ## File attachments Generated services don't upload files. Declare a reference property (`ms project state add --collection note --property photo --type binary --kind image`), regenerate, then upload the bytes and save the returned URL through the generated service: ```ts const uploaded = await fetch('/.ms/state/attachments', { method: 'POST', headers: { 'Content-Type': file.type || 'application/octet-stream' }, // required body: file, }).then((response) => response.json()); // { id, url, contentType, size } const saved = await NoteService.update(note.itemId, { ...noteFields, photo: uploaded.url }); ``` Display it with `<img src={note.photo} />`. - Save within **15 minutes**, or the unreferenced upload is garbage-collected. Store `url` verbatim. - Attachments have no DELETE or PUT: save the property as `null` (or delete the item) to remove one, and upload a new file to replace it. A file belongs to one item (`409` otherwise). - No filename is stored; add a separate property if needed. Limits: 10 MiB per file, 10,000 files and 1 GiB per app. Use a real image `Content-Type` for `<img>`; SVG is always downloaded. ## Preview has its own state `ms app play --mode preview --commit <sha>` (full SHA, after `ms app build --commit <sha>`) runs the app against a **separate Preview store**: same collections, different records. Test writes, validation, and schema/index changes there before `ms app deploy`. Preview only engages when the previewed commit differs from the deployed one. After deploying, click **Refresh** on the app's *New version available* banner before testing schema changes; a plain reload keeps the old schema. To purge Preview records (with the user's explicit approval, see rules), run `ms project state clear --force --json --non-interactive` in the app folder. `isComplete: false` is normal because deletion finishes in the background; don't retry, and wait a minute or two before relaunching Preview or deploying. ## Rules / gotchas - **Feature gate first.** Never use this skill's state workflow before `ms feature status --name state --json` reports `feature.enabled: true`. - **Schema changes are CLI-only.** Never patch the schema JSON to add properties, constraints, indexes, locale, or validation settings. The only exception is per-user ownership, as described above. - **Unsupported schema shapes need a decision.** If the requested design needs nested objects, arrays, enums, `$ref`, composition keywords, `pattern`, or defaults and the CLI cannot represent it, stop and ask. Do not silently switch to manual schema editing. - **Indexes are add-only.** The CLI rejects removing an index or changing its options, deployed or
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る