From a574d0df47034cb9c0506025cc318394226af0ec Mon Sep 17 00:00:00 2001 From: amondnet <1964421+amondnet@users.noreply.github.com> Date: Mon, 21 Sep 2026 06:32:23 +0000 Subject: [PATCH] fix: update vendored skills to latest versions --- plugins/deno/.claude/skills/deno | 1 + plugins/deno/.claude/skills/deno-deploy | 1 + plugins/deno/.claude/skills/deno-frontend | 1 + plugins/deno/.claude/skills/deno-sandbox | 1 + plugins/deno/.claude/skills/migrate-to-deno | 1 + .../deno/agent/skills/deno-deploy/SKILL.md | 638 ++++++++++++++++++ .../deno-deploy/references/AUTHENTICATION.md | 185 +++++ .../deno-deploy/references/DATABASES.md | 159 +++++ .../skills/deno-deploy/references/DENO_KV.md | 153 +++++ .../skills/deno-deploy/references/DOMAINS.md | 93 +++ .../deno-deploy/references/FRAMEWORKS.md | 215 ++++++ .../deno-deploy/references/ORGANIZATIONS.md | 86 +++ .../skills/deno-deploy/references/RUNTIME.md | 103 +++ .../deno-deploy/references/TROUBLESHOOTING.md | 191 ++++++ .../deno/agent/skills/deno-frontend/SKILL.md | 89 +++ .../skills/deno-frontend/references/FRESH.md | 286 ++++++++ .../references/FRESH_MIGRATION.md | 70 ++ .../deno/agent/skills/deno-sandbox/SKILL.md | 413 ++++++++++++ plugins/deno/agent/skills/deno/SKILL.md | 285 ++++++++ .../deno/agent/skills/deno/references/CLI.md | 197 ++++++ .../agent/skills/migrate-to-deno/SKILL.md | 172 +++++ .../migrate-to-deno/references/FROM_BUN.md | 136 ++++ .../migrate-to-deno/references/FROM_NPM.md | 68 ++ .../migrate-to-deno/references/FROM_PNPM.md | 70 ++ .../migrate-to-deno/references/FROM_YARN.md | 69 ++ .../migrate-to-deno/references/NODE_APIS.md | 110 +++ plugins/emulate/.agents/skills/apple/SKILL.md | 2 +- plugins/emulate/.agents/skills/aws/SKILL.md | 4 +- .../emulate/.agents/skills/emulate/SKILL.md | 132 +++- .../emulate/.agents/skills/github/SKILL.md | 25 +- .../emulate/.agents/skills/google/SKILL.md | 12 +- .../emulate/.agents/skills/microsoft/SKILL.md | 5 +- plugins/emulate/.agents/skills/next/SKILL.md | 2 +- .../emulate/.agents/skills/resend/SKILL.md | 14 +- plugins/emulate/.agents/skills/slack/SKILL.md | 2 + .../emulate/.agents/skills/stripe/SKILL.md | 2 +- .../emulate/.agents/skills/vercel/SKILL.md | 2 +- plugins/emulate/agent/skills/aws/SKILL.md | 2 +- plugins/emulate/agent/skills/emulate/SKILL.md | 143 +++- plugins/emulate/agent/skills/github/SKILL.md | 23 +- plugins/emulate/agent/skills/google/SKILL.md | 10 +- .../emulate/agent/skills/microsoft/SKILL.md | 3 +- plugins/emulate/agent/skills/resend/SKILL.md | 12 + plugins/emulate/agent/skills/slack/SKILL.md | 2 + plugins/emulate/skills-lock.json | 22 +- .../skills/firebase-ai-logic-basics/SKILL.md | 29 +- .../references/ios_setup.md | 9 +- .../references/usage_patterns_android.md | 8 +- .../references/usage_patterns_web.md | 6 +- .../references/client_sdk_android.md | 2 +- .../references/android_setup.md | 11 +- .../references/ios_setup.md | 5 +- .../skills/firebase-firestore/SKILL.md | 15 +- .../enterprise/android_sdk_usage.md | 9 +- .../references/enterprise/data_model.md | 15 +- .../references/enterprise/indexes.md | 34 +- .../references/enterprise/python_sdk_usage.md | 6 +- .../references/enterprise/web_sdk_usage.md | 14 +- .../references/standard/android_sdk_usage.md | 10 +- .../references/standard/flutter_setup.md | 8 +- .../references/standard/indexes.md | 34 +- .../firebase-security-rules-auditor/SKILL.md | 23 +- .../skills/firestore-rules-creation/SKILL.md | 18 +- .../skills/extension-to-functions-codebase | 1 + .../.claude/skills/firebase-ai-logic-basics | 1 + .../skills/firebase-app-hosting-basics | 1 + .../.claude/skills/firebase-auth-basics | 1 + .../firebase/.claude/skills/firebase-basics | 1 + .../.claude/skills/firebase-crashlytics | 1 + .../.claude/skills/firebase-data-connect | 1 + .../.claude/skills/firebase-firestore | 1 + .../.claude/skills/firebase-hosting-basics | 1 + .../skills/firebase-remote-config-basics | 1 + .../skills/firebase-security-rules-auditor | 1 + .../.claude/skills/firestore-rules-creation | 1 + .../.claude/skills/xcode-project-setup | 1 + .../extension-to-functions-codebase/SKILL.md | 131 ++++ .../references/configuration-migration.md | 161 +++++ .../references/destructuring-shim.md | 122 ++++ .../references/signature-mapping.md | 84 +++ .../skills/firebase-ai-logic-basics/SKILL.md | 205 ++++++ .../references/flutter_setup.md | 98 +++ .../references/ios_setup.md | 155 +++++ .../references/usage_patterns_android.md | 157 +++++ .../references/usage_patterns_web.md | 186 +++++ .../firebase-app-hosting-basics/SKILL.md | 80 +++ .../references/cli_commands.md | 85 +++ .../references/configuration.md | 59 ++ .../references/emulation.md | 59 ++ .../skills/firebase-auth-basics/SKILL.md | 123 ++++ .../references/client_sdk_android.md | 160 +++++ .../references/client_sdk_web.md | 301 +++++++++ .../references/flutter_setup.md | 149 ++++ .../references/ios_setup.md | 87 +++ .../references/security_rules.md | 49 ++ .../agent/skills/firebase-basics/SKILL.md | 152 +++++ .../references/android_setup.md | 41 ++ .../references/firebase-cli-guide.md | 18 + .../references/firebase-service-init.md | 20 + .../references/flutter_setup.md | 143 ++++ .../firebase-basics/references/ios_setup.md | 113 ++++ .../references/local-env-setup.md | 80 +++ .../references/refresh/android_studio.md | 41 ++ .../references/refresh/antigravity.md | 64 ++ .../references/refresh/claude.md | 12 + .../references/refresh/gemini-cli.md | 13 + .../references/refresh/other-agents.md | 67 ++ .../references/setup/android_studio.md | 23 + .../references/setup/antigravity.md | 98 +++ .../references/setup/claude_code.md | 45 ++ .../references/setup/cursor.md | 93 +++ .../references/setup/gemini_cli.md | 53 ++ .../references/setup/github_copilot.md | 104 +++ .../references/setup/other_agents.md | 99 +++ .../firebase-basics/references/web_setup.md | 77 +++ .../skills/firebase-crashlytics/SKILL.md | 48 ++ .../references/android_setup.md | 155 +++++ .../references/ios_setup.md | 114 ++++ .../skills/firebase-data-connect/SKILL.md | 196 ++++++ .../skills/firebase-data-connect/examples.md | 638 ++++++++++++++++++ .../reference/cloud_functions.md | 184 +++++ .../firebase-data-connect/reference/config.md | 271 ++++++++ .../reference/data_seeding.md | 185 +++++ .../reference/native_sql.md | 170 +++++ .../reference/operations.md | 385 +++++++++++ .../reference/realtime.md | 210 ++++++ .../firebase-data-connect/reference/schema.md | 290 ++++++++ .../reference/sdk_admin_node.md | 141 ++++ .../reference/sdk_android.md | 126 ++++ .../reference/sdk_flutter.md | 134 ++++ .../reference/sdk_ios.md | 157 +++++ .../reference/sdk_web.md | 146 ++++ .../firebase-data-connect/reference/search.md | 264 ++++++++ .../reference/security.md | 295 ++++++++ .../skills/firebase-data-connect/templates.md | 318 +++++++++ .../agent/skills/firebase-firestore/SKILL.md | 98 +++ .../enterprise/android_sdk_usage.md | 231 +++++++ .../references/enterprise/data_model.md | 75 ++ .../references/enterprise/flutter_setup.md | 180 +++++ .../references/enterprise/indexes.md | 133 ++++ .../references/enterprise/ios_setup.md | 189 ++++++ .../references/enterprise/provisioning.md | 118 ++++ .../references/enterprise/python_sdk_usage.md | 142 ++++ .../references/enterprise/web_sdk_usage.md | 127 ++++ .../references/standard/android_sdk_usage.md | 193 ++++++ .../references/standard/flutter_setup.md | 176 +++++ .../references/standard/indexes.md | 111 +++ .../references/standard/ios_setup.md | 174 +++++ .../references/standard/provisioning.md | 110 +++ .../references/standard/web_sdk_usage.md | 192 ++++++ .../skills/firebase-hosting-basics/SKILL.md | 70 ++ .../references/configuration.md | 115 ++++ .../references/deploying.md | 48 ++ .../firebase-remote-config-basics/SKILL.md | 133 ++++ .../references/android_setup.md | 91 +++ .../references/ios_setup.md | 89 +++ .../firebase-security-rules-auditor/SKILL.md | 87 +++ .../skills/firestore-rules-creation/SKILL.md | 587 ++++++++++++++++ .../agent/skills/xcode-project-setup/SKILL.md | 143 ++++ .../scripts/xcode_spm_setup/.gitignore | 9 + .../scripts/xcode_spm_setup/Package.resolved | 41 ++ .../scripts/xcode_spm_setup/Package.swift | 17 + .../xcode_spm_setup/Sources/main.swift | 232 +++++++ plugins/firebase/skills-lock.json | 12 +- plugins/mastra/.agents/skills/mastra/SKILL.md | 5 +- .../skills/mastra/references/mastra-api.md | 5 + .../skills/mastra/references/trace-query.md | 98 +++ plugins/mastra/agent/skills/mastra/SKILL.md | 5 +- .../skills/mastra/references/mastra-api.md | 5 + .../skills/mastra/references/trace-query.md | 98 +++ plugins/mastra/skills-lock.json | 2 +- .../skills/nuxt-seo/agents/openai.yaml | 5 + .../agent/skills/nuxt-seo/agents/openai.yaml | 5 + plugins/nuxt-seo/skills-lock.json | 2 +- .../guidelines/component-selection.md | 2 +- .../references/guidelines/conventions.md | 3 +- .../nuxt-ui/references/guidelines/forms.md | 8 +- .../skills/nuxt-ui/references/layouts/chat.md | 2 +- .../guidelines/component-selection.md | 2 +- .../references/guidelines/conventions.md | 3 +- .../nuxt-ui/references/guidelines/forms.md | 8 +- .../skills/nuxt-ui/references/layouts/chat.md | 2 +- plugins/nuxt-ui/skills-lock.json | 2 +- .../orpc/.agents/skills/orpc-migrate/SKILL.md | 3 +- plugins/orpc/.claude/skills/orpc | 1 + plugins/orpc/.claude/skills/orpc-contract | 1 + plugins/orpc/.claude/skills/orpc-migrate | 1 + plugins/orpc/.claude/skills/orpc-openapi | 1 + .../orpc/agent/skills/orpc-contract/SKILL.md | 167 +++++ .../orpc/agent/skills/orpc-migrate/SKILL.md | 131 ++++ .../orpc/agent/skills/orpc-openapi/SKILL.md | 161 +++++ plugins/orpc/agent/skills/orpc/SKILL.md | 248 +++++++ plugins/orpc/skills-lock.json | 2 +- .../portless/.agents/skills/portless/SKILL.md | 2 + .../portless/agent/skills/portless/SKILL.md | 2 + plugins/portless/skills-lock.json | 2 +- .../vercel-react-native-skills/metadata.json | 16 + .../vercel-react-native-skills/metadata.json | 16 + plugins/react-native/skills-lock.json | 2 +- .../vercel-composition-patterns/metadata.json | 11 + .../vercel-react-best-practices/metadata.json | 15 + .../metadata.json | 12 + .../vercel-composition-patterns/metadata.json | 11 + .../vercel-react-best-practices/metadata.json | 15 + .../metadata.json | 12 + plugins/react/skills-lock.json | 6 +- .../slidev/references/code-magic-move.md | 13 + .../skills/slidev/references/core-cli.md | 2 +- .../slidev/references/core-exporting.md | 5 +- .../slidev/references/code-magic-move.md | 13 + .../skills/slidev/references/core-cli.md | 2 +- .../slidev/references/core-exporting.md | 5 +- plugins/slidev/skills-lock.json | 2 +- .../.agents/skills/turborepo/SKILL.md | 4 +- .../references/best-practices/structure.md | 4 +- .../references/configuration/RULE.md | 4 +- .../references/configuration/tasks.md | 24 + .../turborepo/references/environment/RULE.md | 2 +- .../references/environment/gotchas.md | 4 +- .../turborepo/agent/skills/turborepo/SKILL.md | 4 +- .../references/best-practices/structure.md | 4 +- .../references/configuration/RULE.md | 4 +- .../references/configuration/tasks.md | 24 + .../turborepo/references/environment/RULE.md | 2 +- .../references/environment/gotchas.md | 4 +- plugins/turborepo/skills-lock.json | 2 +- plugins/vercel-sandbox/skills-lock.json | 2 +- .../.agents/skills/vueuse-functions/SKILL.md | 4 +- .../references/injectLocal.md | 2 +- .../references/useBreakpoints.md | 2 +- .../vueuse-functions/references/useCloned.md | 2 +- .../references/useCountdown.md | 13 - .../references/useElementByPoint.md | 4 - .../references/useIDBKeyval.md | 20 +- .../references/useIntersectionObserver.md | 28 + .../references/useLiveAnnouncer.md | 77 +++ .../references/useMediaQuery.md | 2 +- .../vueuse-functions/references/useMemory.md | 19 +- .../vueuse-functions/references/useNow.md | 14 - .../references/usePerformanceObserver.md | 4 +- .../references/useRefHistory.md | 2 +- .../vueuse-functions/references/useStepper.md | 7 + .../references/useTemporalNow.md | 321 +++++++++ .../references/useThrottleFn.md | 2 +- .../vueuse-functions/references/useTimeAgo.md | 7 - .../references/useTimeAgoIntl.md | 7 - .../references/useTimestamp.md | 14 - .../vueuse-functions/references/useVibrate.md | 10 - .../vueuse-functions/references/useWebMCP.md | 245 +++++++ .../references/useWebSocket.md | 7 - .../references/watchIgnorable.md | 2 +- .../agent/skills/vueuse-functions/SKILL.md | 4 +- .../references/injectLocal.md | 2 +- .../references/useBreakpoints.md | 2 +- .../vueuse-functions/references/useCloned.md | 2 +- .../references/useCountdown.md | 13 - .../references/useElementByPoint.md | 4 - .../references/useIDBKeyval.md | 20 +- .../references/useIntersectionObserver.md | 28 + .../references/useLiveAnnouncer.md | 77 +++ .../references/useMediaQuery.md | 2 +- .../vueuse-functions/references/useMemory.md | 19 +- .../vueuse-functions/references/useNow.md | 14 - .../references/usePerformanceObserver.md | 4 +- .../references/useRefHistory.md | 2 +- .../vueuse-functions/references/useStepper.md | 7 + .../references/useTemporalNow.md | 321 +++++++++ .../references/useThrottleFn.md | 2 +- .../vueuse-functions/references/useTimeAgo.md | 7 - .../references/useTimeAgoIntl.md | 7 - .../references/useTimestamp.md | 14 - .../vueuse-functions/references/useVibrate.md | 10 - .../vueuse-functions/references/useWebMCP.md | 245 +++++++ .../references/useWebSocket.md | 7 - .../references/watchIgnorable.md | 2 +- plugins/vueuse/skills-lock.json | 2 +- 276 files changed, 19073 insertions(+), 427 deletions(-) create mode 120000 plugins/deno/.claude/skills/deno create mode 120000 plugins/deno/.claude/skills/deno-deploy create mode 120000 plugins/deno/.claude/skills/deno-frontend create mode 120000 plugins/deno/.claude/skills/deno-sandbox create mode 120000 plugins/deno/.claude/skills/migrate-to-deno create mode 100644 plugins/deno/agent/skills/deno-deploy/SKILL.md create mode 100644 plugins/deno/agent/skills/deno-deploy/references/AUTHENTICATION.md create mode 100644 plugins/deno/agent/skills/deno-deploy/references/DATABASES.md create mode 100644 plugins/deno/agent/skills/deno-deploy/references/DENO_KV.md create mode 100644 plugins/deno/agent/skills/deno-deploy/references/DOMAINS.md create mode 100644 plugins/deno/agent/skills/deno-deploy/references/FRAMEWORKS.md create mode 100644 plugins/deno/agent/skills/deno-deploy/references/ORGANIZATIONS.md create mode 100644 plugins/deno/agent/skills/deno-deploy/references/RUNTIME.md create mode 100644 plugins/deno/agent/skills/deno-deploy/references/TROUBLESHOOTING.md create mode 100644 plugins/deno/agent/skills/deno-frontend/SKILL.md create mode 100644 plugins/deno/agent/skills/deno-frontend/references/FRESH.md create mode 100644 plugins/deno/agent/skills/deno-frontend/references/FRESH_MIGRATION.md create mode 100644 plugins/deno/agent/skills/deno-sandbox/SKILL.md create mode 100644 plugins/deno/agent/skills/deno/SKILL.md create mode 100644 plugins/deno/agent/skills/deno/references/CLI.md create mode 100644 plugins/deno/agent/skills/migrate-to-deno/SKILL.md create mode 100644 plugins/deno/agent/skills/migrate-to-deno/references/FROM_BUN.md create mode 100644 plugins/deno/agent/skills/migrate-to-deno/references/FROM_NPM.md create mode 100644 plugins/deno/agent/skills/migrate-to-deno/references/FROM_PNPM.md create mode 100644 plugins/deno/agent/skills/migrate-to-deno/references/FROM_YARN.md create mode 100644 plugins/deno/agent/skills/migrate-to-deno/references/NODE_APIS.md create mode 120000 plugins/firebase/.claude/skills/extension-to-functions-codebase create mode 120000 plugins/firebase/.claude/skills/firebase-ai-logic-basics create mode 120000 plugins/firebase/.claude/skills/firebase-app-hosting-basics create mode 120000 plugins/firebase/.claude/skills/firebase-auth-basics create mode 120000 plugins/firebase/.claude/skills/firebase-basics create mode 120000 plugins/firebase/.claude/skills/firebase-crashlytics create mode 120000 plugins/firebase/.claude/skills/firebase-data-connect create mode 120000 plugins/firebase/.claude/skills/firebase-firestore create mode 120000 plugins/firebase/.claude/skills/firebase-hosting-basics create mode 120000 plugins/firebase/.claude/skills/firebase-remote-config-basics create mode 120000 plugins/firebase/.claude/skills/firebase-security-rules-auditor create mode 120000 plugins/firebase/.claude/skills/firestore-rules-creation create mode 120000 plugins/firebase/.claude/skills/xcode-project-setup create mode 100644 plugins/firebase/agent/skills/extension-to-functions-codebase/SKILL.md create mode 100644 plugins/firebase/agent/skills/extension-to-functions-codebase/references/configuration-migration.md create mode 100644 plugins/firebase/agent/skills/extension-to-functions-codebase/references/destructuring-shim.md create mode 100644 plugins/firebase/agent/skills/extension-to-functions-codebase/references/signature-mapping.md create mode 100644 plugins/firebase/agent/skills/firebase-ai-logic-basics/SKILL.md create mode 100644 plugins/firebase/agent/skills/firebase-ai-logic-basics/references/flutter_setup.md create mode 100644 plugins/firebase/agent/skills/firebase-ai-logic-basics/references/ios_setup.md create mode 100644 plugins/firebase/agent/skills/firebase-ai-logic-basics/references/usage_patterns_android.md create mode 100644 plugins/firebase/agent/skills/firebase-ai-logic-basics/references/usage_patterns_web.md create mode 100644 plugins/firebase/agent/skills/firebase-app-hosting-basics/SKILL.md create mode 100644 plugins/firebase/agent/skills/firebase-app-hosting-basics/references/cli_commands.md create mode 100644 plugins/firebase/agent/skills/firebase-app-hosting-basics/references/configuration.md create mode 100644 plugins/firebase/agent/skills/firebase-app-hosting-basics/references/emulation.md create mode 100644 plugins/firebase/agent/skills/firebase-auth-basics/SKILL.md create mode 100644 plugins/firebase/agent/skills/firebase-auth-basics/references/client_sdk_android.md create mode 100644 plugins/firebase/agent/skills/firebase-auth-basics/references/client_sdk_web.md create mode 100644 plugins/firebase/agent/skills/firebase-auth-basics/references/flutter_setup.md create mode 100644 plugins/firebase/agent/skills/firebase-auth-basics/references/ios_setup.md create mode 100644 plugins/firebase/agent/skills/firebase-auth-basics/references/security_rules.md create mode 100644 plugins/firebase/agent/skills/firebase-basics/SKILL.md create mode 100644 plugins/firebase/agent/skills/firebase-basics/references/android_setup.md create mode 100644 plugins/firebase/agent/skills/firebase-basics/references/firebase-cli-guide.md create mode 100644 plugins/firebase/agent/skills/firebase-basics/references/firebase-service-init.md create mode 100644 plugins/firebase/agent/skills/firebase-basics/references/flutter_setup.md create mode 100644 plugins/firebase/agent/skills/firebase-basics/references/ios_setup.md create mode 100644 plugins/firebase/agent/skills/firebase-basics/references/local-env-setup.md create mode 100644 plugins/firebase/agent/skills/firebase-basics/references/refresh/android_studio.md create mode 100644 plugins/firebase/agent/skills/firebase-basics/references/refresh/antigravity.md create mode 100644 plugins/firebase/agent/skills/firebase-basics/references/refresh/claude.md create mode 100644 plugins/firebase/agent/skills/firebase-basics/references/refresh/gemini-cli.md create mode 100644 plugins/firebase/agent/skills/firebase-basics/references/refresh/other-agents.md create mode 100644 plugins/firebase/agent/skills/firebase-basics/references/setup/android_studio.md create mode 100644 plugins/firebase/agent/skills/firebase-basics/references/setup/antigravity.md create mode 100644 plugins/firebase/agent/skills/firebase-basics/references/setup/claude_code.md create mode 100644 plugins/firebase/agent/skills/firebase-basics/references/setup/cursor.md create mode 100644 plugins/firebase/agent/skills/firebase-basics/references/setup/gemini_cli.md create mode 100644 plugins/firebase/agent/skills/firebase-basics/references/setup/github_copilot.md create mode 100644 plugins/firebase/agent/skills/firebase-basics/references/setup/other_agents.md create mode 100644 plugins/firebase/agent/skills/firebase-basics/references/web_setup.md create mode 100644 plugins/firebase/agent/skills/firebase-crashlytics/SKILL.md create mode 100644 plugins/firebase/agent/skills/firebase-crashlytics/references/android_setup.md create mode 100644 plugins/firebase/agent/skills/firebase-crashlytics/references/ios_setup.md create mode 100644 plugins/firebase/agent/skills/firebase-data-connect/SKILL.md create mode 100644 plugins/firebase/agent/skills/firebase-data-connect/examples.md create mode 100644 plugins/firebase/agent/skills/firebase-data-connect/reference/cloud_functions.md create mode 100644 plugins/firebase/agent/skills/firebase-data-connect/reference/config.md create mode 100644 plugins/firebase/agent/skills/firebase-data-connect/reference/data_seeding.md create mode 100644 plugins/firebase/agent/skills/firebase-data-connect/reference/native_sql.md create mode 100644 plugins/firebase/agent/skills/firebase-data-connect/reference/operations.md create mode 100644 plugins/firebase/agent/skills/firebase-data-connect/reference/realtime.md create mode 100644 plugins/firebase/agent/skills/firebase-data-connect/reference/schema.md create mode 100644 plugins/firebase/agent/skills/firebase-data-connect/reference/sdk_admin_node.md create mode 100644 plugins/firebase/agent/skills/firebase-data-connect/reference/sdk_android.md create mode 100644 plugins/firebase/agent/skills/firebase-data-connect/reference/sdk_flutter.md create mode 100644 plugins/firebase/agent/skills/firebase-data-connect/reference/sdk_ios.md create mode 100644 plugins/firebase/agent/skills/firebase-data-connect/reference/sdk_web.md create mode 100644 plugins/firebase/agent/skills/firebase-data-connect/reference/search.md create mode 100644 plugins/firebase/agent/skills/firebase-data-connect/reference/security.md create mode 100644 plugins/firebase/agent/skills/firebase-data-connect/templates.md create mode 100644 plugins/firebase/agent/skills/firebase-firestore/SKILL.md create mode 100644 plugins/firebase/agent/skills/firebase-firestore/references/enterprise/android_sdk_usage.md create mode 100644 plugins/firebase/agent/skills/firebase-firestore/references/enterprise/data_model.md create mode 100644 plugins/firebase/agent/skills/firebase-firestore/references/enterprise/flutter_setup.md create mode 100644 plugins/firebase/agent/skills/firebase-firestore/references/enterprise/indexes.md create mode 100644 plugins/firebase/agent/skills/firebase-firestore/references/enterprise/ios_setup.md create mode 100644 plugins/firebase/agent/skills/firebase-firestore/references/enterprise/provisioning.md create mode 100644 plugins/firebase/agent/skills/firebase-firestore/references/enterprise/python_sdk_usage.md create mode 100644 plugins/firebase/agent/skills/firebase-firestore/references/enterprise/web_sdk_usage.md create mode 100644 plugins/firebase/agent/skills/firebase-firestore/references/standard/android_sdk_usage.md create mode 100644 plugins/firebase/agent/skills/firebase-firestore/references/standard/flutter_setup.md create mode 100644 plugins/firebase/agent/skills/firebase-firestore/references/standard/indexes.md create mode 100644 plugins/firebase/agent/skills/firebase-firestore/references/standard/ios_setup.md create mode 100644 plugins/firebase/agent/skills/firebase-firestore/references/standard/provisioning.md create mode 100644 plugins/firebase/agent/skills/firebase-firestore/references/standard/web_sdk_usage.md create mode 100644 plugins/firebase/agent/skills/firebase-hosting-basics/SKILL.md create mode 100644 plugins/firebase/agent/skills/firebase-hosting-basics/references/configuration.md create mode 100644 plugins/firebase/agent/skills/firebase-hosting-basics/references/deploying.md create mode 100644 plugins/firebase/agent/skills/firebase-remote-config-basics/SKILL.md create mode 100644 plugins/firebase/agent/skills/firebase-remote-config-basics/references/android_setup.md create mode 100644 plugins/firebase/agent/skills/firebase-remote-config-basics/references/ios_setup.md create mode 100644 plugins/firebase/agent/skills/firebase-security-rules-auditor/SKILL.md create mode 100644 plugins/firebase/agent/skills/firestore-rules-creation/SKILL.md create mode 100644 plugins/firebase/agent/skills/xcode-project-setup/SKILL.md create mode 100644 plugins/firebase/agent/skills/xcode-project-setup/scripts/xcode_spm_setup/.gitignore create mode 100644 plugins/firebase/agent/skills/xcode-project-setup/scripts/xcode_spm_setup/Package.resolved create mode 100644 plugins/firebase/agent/skills/xcode-project-setup/scripts/xcode_spm_setup/Package.swift create mode 100644 plugins/firebase/agent/skills/xcode-project-setup/scripts/xcode_spm_setup/Sources/main.swift create mode 100644 plugins/mastra/.agents/skills/mastra/references/trace-query.md create mode 100644 plugins/mastra/agent/skills/mastra/references/trace-query.md create mode 100644 plugins/nuxt-seo/.agents/skills/nuxt-seo/agents/openai.yaml create mode 100644 plugins/nuxt-seo/agent/skills/nuxt-seo/agents/openai.yaml create mode 120000 plugins/orpc/.claude/skills/orpc create mode 120000 plugins/orpc/.claude/skills/orpc-contract create mode 120000 plugins/orpc/.claude/skills/orpc-migrate create mode 120000 plugins/orpc/.claude/skills/orpc-openapi create mode 100644 plugins/orpc/agent/skills/orpc-contract/SKILL.md create mode 100644 plugins/orpc/agent/skills/orpc-migrate/SKILL.md create mode 100644 plugins/orpc/agent/skills/orpc-openapi/SKILL.md create mode 100644 plugins/orpc/agent/skills/orpc/SKILL.md create mode 100644 plugins/react-native/.agents/skills/vercel-react-native-skills/metadata.json create mode 100644 plugins/react-native/agent/skills/vercel-react-native-skills/metadata.json create mode 100644 plugins/react/.agents/skills/vercel-composition-patterns/metadata.json create mode 100644 plugins/react/.agents/skills/vercel-react-best-practices/metadata.json create mode 100644 plugins/react/.agents/skills/vercel-react-view-transitions/metadata.json create mode 100644 plugins/react/agent/skills/vercel-composition-patterns/metadata.json create mode 100644 plugins/react/agent/skills/vercel-react-best-practices/metadata.json create mode 100644 plugins/react/agent/skills/vercel-react-view-transitions/metadata.json create mode 100644 plugins/vueuse/.agents/skills/vueuse-functions/references/useLiveAnnouncer.md create mode 100644 plugins/vueuse/.agents/skills/vueuse-functions/references/useTemporalNow.md create mode 100644 plugins/vueuse/.agents/skills/vueuse-functions/references/useWebMCP.md create mode 100644 plugins/vueuse/agent/skills/vueuse-functions/references/useLiveAnnouncer.md create mode 100644 plugins/vueuse/agent/skills/vueuse-functions/references/useTemporalNow.md create mode 100644 plugins/vueuse/agent/skills/vueuse-functions/references/useWebMCP.md diff --git a/plugins/deno/.claude/skills/deno b/plugins/deno/.claude/skills/deno new file mode 120000 index 00000000..b611fe2e --- /dev/null +++ b/plugins/deno/.claude/skills/deno @@ -0,0 +1 @@ +../../.agents/skills/deno \ No newline at end of file diff --git a/plugins/deno/.claude/skills/deno-deploy b/plugins/deno/.claude/skills/deno-deploy new file mode 120000 index 00000000..81d72423 --- /dev/null +++ b/plugins/deno/.claude/skills/deno-deploy @@ -0,0 +1 @@ +../../.agents/skills/deno-deploy \ No newline at end of file diff --git a/plugins/deno/.claude/skills/deno-frontend b/plugins/deno/.claude/skills/deno-frontend new file mode 120000 index 00000000..6ac5f920 --- /dev/null +++ b/plugins/deno/.claude/skills/deno-frontend @@ -0,0 +1 @@ +../../.agents/skills/deno-frontend \ No newline at end of file diff --git a/plugins/deno/.claude/skills/deno-sandbox b/plugins/deno/.claude/skills/deno-sandbox new file mode 120000 index 00000000..9a2abf28 --- /dev/null +++ b/plugins/deno/.claude/skills/deno-sandbox @@ -0,0 +1 @@ +../../.agents/skills/deno-sandbox \ No newline at end of file diff --git a/plugins/deno/.claude/skills/migrate-to-deno b/plugins/deno/.claude/skills/migrate-to-deno new file mode 120000 index 00000000..4e7658a7 --- /dev/null +++ b/plugins/deno/.claude/skills/migrate-to-deno @@ -0,0 +1 @@ +../../.agents/skills/migrate-to-deno \ No newline at end of file diff --git a/plugins/deno/agent/skills/deno-deploy/SKILL.md b/plugins/deno/agent/skills/deno-deploy/SKILL.md new file mode 100644 index 00000000..fe3d7f3d --- /dev/null +++ b/plugins/deno/agent/skills/deno-deploy/SKILL.md @@ -0,0 +1,638 @@ +--- +name: deno-deploy +description: Use when deploying Deno apps to production, asking about Deno + Deploy, or working with `deno deploy` CLI commands. Covers deployment + workflows, environment variables, KV database access, custom domains, the + --tunnel flag for local development, and the `deno deploy` command reference. +license: MIT +metadata: + author: denoland + version: "1.5" +--- +# Deno Deploy + +This skill provides guidance for deploying applications to Deno Deploy. + +## Scope Boundaries + +This skill applies **only** to Deno Deploy questions. Follow these rules: + +- If the user asks about **AWS Lambda, Vercel, Netlify, Google Cloud Run, + Docker, Kubernetes, or any other deployment platform**, answer using that + platform directly. Do not mention Deno Deploy at all — not as an alternative, + not as a comparison, not as a suggestion. +- If the user asks about **running a local Deno script** (not deploying), answer + the local question directly. Do not mention Deno Deploy, deployment, or the + `--tunnel` flag. +- Do not include `deno deploy` commands, Deno KV, or Deno Deploy environment + variable configuration in responses about other platforms or local-only + scripts. +- Only discuss Deno Deploy when the user explicitly asks about Deno Deploy or + deploying a Deno application to production. + +## Important: Use `deno deploy`, NOT `deployctl` + +**Always use the `deno deploy` command.** Do NOT use `deployctl`. + +- `deployctl` is for Deno Deploy Classic (deprecated) +- `deno deploy` is the modern, integrated command built into the Deno CLI +- **Requires Deno >= 2.4.2** - the `deno deploy` subcommand was introduced in + Deno 2.4 + +## When Unsure About CLI Flags + +**Always run `--help` before guessing at flags.** The `deno deploy` subcommand +has many flags, and they change between versions. When you're unsure what a +command accepts: + +```bash +# See all subcommands +deno deploy --help + +# See flags for a specific subcommand +deno deploy create --help +deno deploy env --help +deno deploy database --help +``` + +This takes seconds and prevents repeated trial-and-error failures. Never assume +a flag exists — check first. + +## Deployment Workflow + +**Always show the core deploy command first** — then explain diagnostic steps. +When a user asks "how do I deploy?", lead with the actual command +(`deno deploy --prod`) before covering pre-flight checks and configuration. + +### Step 1: Locate the App Directory + +Before running any deploy commands, find where the Deno app is located: + +```bash +# Check if deno.json exists in current directory +if [ -f "deno.json" ] || [ -f "deno.jsonc" ]; then + echo "APP_DIR: $(pwd)" +else + # Look for deno.json in immediate subdirectories + find . -maxdepth 2 -name "deno.json" -o -name "deno.jsonc" 2>/dev/null | head -5 +fi +``` + +All deploy commands must run from the app directory. + +### Step 2: Pre-Flight Checks + +Check Deno version and existing configuration: + +```bash +# Check Deno version (must be >= 2.4.2) +deno --version | head -1 + +# Check for existing deploy config +grep -E '"org"|"app"' deno.json deno.jsonc 2>/dev/null || echo "NO_DEPLOY_CONFIG" +``` + +### Step 3: Check for Startup Dependencies + +Before deploying, check if the app connects to a database or external service at +startup (e.g., top-level `await initDb()` in `main.ts`). If it does, the deploy +will fail during warmup because the database doesn't exist yet. + +**If the app has startup database dependencies, follow this order:** + +1. **Create the app with `--no-wait`** so a warmup failure doesn't block you: + ```bash + deno deploy create \ + --org --app \ + --source local --runtime-mode dynamic --entrypoint main.ts \ + --build-timeout 5 --build-memory-limit 1024 --region us \ + --no-wait + ``` + +2. **Provision and assign the database:** + ```bash + deno deploy database provision my-db --kind prisma --region us-east-1 + deno deploy database assign my-db --app + ``` + +3. **Redeploy** (now the database exists, warmup will succeed): + ```bash + deno deploy --prod + ``` + +If the app has no startup dependencies, skip this step and deploy normally +below. + +### Step 4: Deploy Based on Configuration + +**If `deploy.org` AND `deploy.app` exist in deno.json:** + +```bash +# Build if needed (Fresh, Astro, etc.) +deno task build + +# Deploy to production +deno deploy --prod +``` + +**If NO deploy config exists:** + +**Apps must be created before they can be deployed to.** You cannot run +`deno deploy --prod` until an app exists. + +**IMPORTANT: Ask the user first** - Do they have an existing app on Deno Deploy, +or do they need to create a new one? + +**If they have an existing app**, add the config directly to deno.json: + +```json +{ + "deploy": { + "org": "", + "app": "" + } +} +``` + +The org name is in the Deno Deploy console URL (e.g., +`console.deno.com/your-org-name`). Once this config is in place, subsequent +deploys just need `deno deploy --prod`. + +**If they need to create a new app:** + +The CLI needs an organization name. Find it at https://console.deno.com - the +org is in the URL path (e.g., `console.deno.com/your-org-name`). + +**Interactive creation** (opens a browser — only works when a human is at the +keyboard): + +```bash +deno deploy create --org +# A browser window opens - complete the app creation there +``` + +**Non-interactive creation** (use when an AI agent is performing the deploy, or +in CI/CD): + +```bash +deno deploy create \ + --org \ + --app \ + --source local \ + --runtime-mode dynamic \ + --entrypoint main.ts \ + --build-timeout 5 \ + --build-memory-limit 1024 \ + --region us +``` + +The create command also does the initial deploy. After it completes, `deno.json` +is updated with `deploy.org` and `deploy.app` automatically. From that point on, +subsequent deploys only need: + +```bash +deno deploy --prod +``` + +After completion, verify the config was saved: + +```bash +grep -E '"org"|"app"' deno.json +``` + +**When an AI agent is performing the deployment**, always use the +non-interactive flow with explicit flags. The interactive flow requires browser +windows and terminal prompts that agents cannot navigate. + +## Core Commands + +### Production Deployment + +```bash +deno deploy --prod +``` + +### Preview Deployment + +```bash +deno deploy +``` + +Preview deployments create a unique URL for testing without affecting +production. + +### Targeting Specific Apps + +```bash +deno deploy --org my-org --app my-app --prod +``` + +### Configuring an Entrypoint + +Set the entrypoint in your `deno.json` (this is used by `deno deploy create` +during app creation): + +```json +{ + "deploy": { + "entrypoint": "main.ts" + } +} +``` + +Note: `--entrypoint` is a flag on `deno deploy create`, not on `deno deploy` +itself. + +### Additional Flags + +These flags are available on `deno deploy create` (and apply during the initial +deploy): + +| Flag | Purpose | +| ---------------------- | ---------------------------------------- | +| `--allow-node-modules` | Include node_modules directory in upload | +| `--no-wait` | Skip waiting for the build to complete | + +## Creating Apps (Non-Interactive Reference) + +When any flag beyond `--org` is provided, `deno deploy create` runs in +non-interactive mode — all required flags must be specified. This is the +recommended approach for AI agents and CI/CD pipelines. + +### Required Flags + +| Flag | Description | +| --------------------------- | ----------------------------------------------------- | +| `--org ` | Organization name | +| `--app ` | Application name (becomes your URL: `.deno.dev`) | +| `--source ` | Deploy from local files or a GitHub repo | +| `--build-timeout ` | Build timeout: 5, 10, 15, 20, 25, or 30 | +| `--build-memory-limit ` | Memory limit: 1024, 2048, 3072, or 4096 | +| `--region ` | Deployment region: us, eu, or global | + +### GitHub Source Flags + +When using `--source github`, you also need: + +| Flag | Description | +| ---------------- | ----------------------- | +| `--owner ` | GitHub repository owner | +| `--repo ` | GitHub repository name | + +### Build Configuration Flags + +| Flag | Description | +| ------------------------------------ | ------------------------------------------------------------- | +| `--app-directory ` | Path to app directory (for monorepos) | +| `--framework-preset ` | Framework preset (see [Frameworks](references/FRAMEWORKS.md)) | +| `--install-command ` | Custom install command | +| `--build-command ` | Custom build command | +| `--pre-deploy-command ` | Command to run before deploy | +| `--do-not-use-detected-build-config` | Skip auto-detection of framework config | + +The CLI auto-detects your framework and build configuration. If a framework is +detected, you can skip `--install-command`, `--build-command`, +`--pre-deploy-command`, and `--runtime-mode` — they'll be inferred from the +preset. Use `--do-not-use-detected-build-config` to override detection. **When +using this flag, all three build commands (`--install-command`, +`--build-command`, `--pre-deploy-command`) plus `--runtime-mode` become +required** — omitting any of them causes exit code 2. + +### Runtime Mode Flags + +You must pick a runtime mode with `--runtime-mode ` (unless a +framework preset handles it). + +**Dynamic mode** (for apps with a server): + +| Flag | Description | +| --------------------------- | ------------------------------------------- | +| `--entrypoint ` | Entry file (required for dynamic mode) | +| `--arguments ` | Arguments passed to entrypoint (repeatable) | +| `--working-directory ` | Working directory for the process | + +**Static mode** (for static sites): + +| Flag | Description | +| -------------------- | --------------------------------------------------- | +| `--static-dir ` | Directory to serve static files from (required) | +| `--single-page-app` | Serve index.html for routes that don't match a file | + +### Other Flags + +| Flag | Description | +| ---------------------- | ----------------------------------------------------- | +| `--dry-run` | Validate everything without actually creating the app | +| `--no-wait` | Don't wait for the build to complete | +| `--allow-node-modules` | Include node_modules in the upload | + +### Examples + +**Simple Deno server:** + +```bash +deno deploy create \ + --org my-org --app my-api \ + --source local \ + --runtime-mode dynamic --entrypoint main.ts \ + --build-timeout 5 --build-memory-limit 1024 --region us +``` + +**Fresh app (framework auto-detected):** + +```bash +deno deploy create \ + --org my-org --app my-fresh-app \ + --source local \ + --build-timeout 5 --build-memory-limit 1024 --region us +``` + +**Next.js from GitHub:** + +```bash +deno deploy create \ + --org my-org --app my-next-app \ + --source github --owner my-github-user --repo my-next-repo \ + --framework-preset Next \ + --build-timeout 15 --build-memory-limit 2048 --region us \ + --allow-node-modules +``` + +**Static site:** + +```bash +deno deploy create \ + --org my-org --app my-static-site \ + --source local \ + --runtime-mode static --static-dir dist --single-page-app \ + --build-command "deno task build" \ + --build-timeout 5 --build-memory-limit 1024 --region us +``` + +## Environment Variables + +### Contexts + +Deno Deploy has three "contexts" - logical environments where your code runs, +each with its own set of variables: + +| Context | Purpose | +| --------------- | --------------------------------------- | +| **Production** | Live traffic on your production URL | +| **Development** | Preview deployments and branch URLs | +| **Build** | Only available during the build process | + +You can set different values for the same variable in each context. For example, +you might use a test database URL in Development and the real one in Production. + +### Predefined Variables + +These are automatically available in your code: + +| Variable | Description | +| -------------------- | -------------------------------------- | +| `DENO_DEPLOY` | Always `1` when running on Deno Deploy | +| `DENO_DEPLOYMENT_ID` | Unique ID for the current deployment | +| `DENO_DEPLOY_ORG_ID` | Your organization's ID | +| `DENO_DEPLOY_APP_ID` | Your application's ID | +| `CI` | Set to `1` during builds only | + +### Accessing Variables in Code + +```typescript +const dbUrl = Deno.env.get("DATABASE_URL"); +const isDenoDeploy = Deno.env.get("DENO_DEPLOY") === "1"; +``` + +### Managing Variables via CLI + +```bash +# Add a plain text variable +deno deploy env add DATABASE_URL "postgres://..." + +# Add a secret variable (hidden after creation, only readable in code) +deno deploy env add API_KEY "sk-..." --secret + +# List all variables +deno deploy env list + +# Update just the value (keeps contexts and secret status) +deno deploy env update-value DATABASE_URL "postgres://new-url..." + +# Update which contexts a variable applies to +deno deploy env update-contexts DATABASE_URL production development + +# Delete a variable +deno deploy env delete DATABASE_URL + +# Load from .env file (all values treated as secrets by default) +deno deploy env load .env.production + +# Load from .env file, marking specific keys as non-secrets +deno deploy env load .env.production --non-secrets PUBLIC_URL APP_NAME +``` + +### Variable Types + +- **Plain text** - Visible in the dashboard, good for feature flags and + non-sensitive config +- **Secrets** - Hidden after creation, only readable in your code, use for API + keys and credentials + +### Limits + +- Key names: max 128 bytes +- Values: max 16 KB +- Keys cannot start with `DENO_`, `LD_`, or `OTEL_` + +## Viewing Logs + +```bash +# Stream live logs +deno deploy logs + +# Filter by date range +deno deploy logs --start 2026-01-15 --end 2026-01-16 +``` + +## Databases & Storage + +Deno Deploy provides built-in database support with **automatic environment +isolation**. Each environment (production, preview, branch) gets its own +isolated database automatically. + +### Available Options + +| Engine | Use Case | +| -------------- | -------------------------------------------------------- | +| **Deno KV** | Key-value storage, simple data, counters, sessions | +| **PostgreSQL** | Relational data, complex queries, existing Postgres apps | + +### Deno KV Quick Start + +No configuration needed - just use the built-in API: + +```typescript +const kv = await Deno.openKv(); + +// Store data +await kv.set(["users", "alice"], { name: "Alice", role: "admin" }); + +// Retrieve data +const user = await kv.get(["users", "alice"]); +console.log(user.value); // { name: "Alice", role: "admin" } + +// List by prefix +for await (const entry of kv.list({ prefix: ["users"] })) { + console.log(entry.key, entry.value); +} +``` + +Deno Deploy automatically connects to the correct database based on your +environment. + +### PostgreSQL + +For PostgreSQL, Deno Deploy injects environment variables (`DATABASE_URL`, +`PGHOST`, etc.) that most libraries detect automatically: + +```typescript +// Recommended: npm:pg (best PostgreSQL driver for Deno Deploy) +import pg from "npm:pg"; +const pool = new pg.Pool(); // Reads DATABASE_URL from environment automatically +``` + +### Provisioning + +Use the `deno deploy database` command to provision and manage databases: + +```bash +# Provision a Deno KV database +deno deploy database provision my-database --kind denokv + +# Provision a Prisma PostgreSQL database +deno deploy database provision my-database --kind prisma --region us-east-1 + +# Assign to your app +deno deploy database assign my-database --app my-app +``` + +For detailed CLI commands, see [Databases](references/DATABASES.md). + +### Local Development + +Use `--tunnel` to connect to your hosted development database locally: + +```bash +deno task --tunnel dev +``` + +See [Databases](references/DATABASES.md) and [Deno KV](references/DENO_KV.md) +for detailed documentation. + +## Local Development Tunnel + +The tunnel feature lets you expose your local development server to the +internet. This is useful for: + +- **Testing webhooks** - Receive webhook callbacks from external services +- **Sharing with teammates** - Let others preview your local work +- **Mobile testing** - Access your local server from other devices + +### Basic Usage + +Add the `--tunnel` flag when running your app: + +```bash +deno run --tunnel -A main.ts +``` + +The first time you run this, it will: + +1. Ask you to authenticate with Deno Deploy (opens a browser) +2. Ask you to select which app to connect the tunnel to +3. Generate a public URL that forwards requests to your local server + +### Using with Tasks + +You can use `--tunnel` with your existing tasks in `deno.json`: + +```bash +deno task --tunnel dev +``` + +This runs your `dev` task with the tunnel enabled. + +### What the Tunnel Provides + +Beyond just forwarding requests, the tunnel also: + +- **Syncs environment variables** - Variables set in your Deno Deploy app's + "Local" context become available to your local process +- **Sends logs and metrics** - OpenTelemetry data goes to the Deno Deploy + dashboard (filter with `context:local`) +- **Connects to databases** - Automatically connects to your assigned local + development databases + +### Managing Tunnels + +- View active tunnels in the Deno Deploy dashboard under the "Tunnels" tab +- Stop a tunnel by terminating the Deno process (Ctrl+C) + +## Command Reference + +| Command | Purpose | +| ----------------------------------------------------- | ------------------------------------------------------ | +| `deno deploy --prod` | Deploy to production (app must exist first) | +| `deno deploy` | Preview deployment | +| `deno deploy create --org ` | Create new app (interactive) | +| `deno deploy create --org --app ...` | Create new app (non-interactive, see full flags above) | +| `deno deploy create ... --no-wait` | Create app without waiting for build to complete | +| `deno deploy create ... --allow-node-modules` | Create app including node_modules | +| `deno deploy env add ` | Add plain text environment variable | +| `deno deploy env add --secret` | Add secret environment variable | +| `deno deploy env list` | List environment variables | +| `deno deploy env update-value ` | Update variable value (keeps contexts/secret status) | +| `deno deploy env update-contexts ` | Update which contexts a variable applies to | +| `deno deploy env delete ` | Delete environment variable | +| `deno deploy env load ` | Load variables from .env file (defaults to secret) | +| `deno deploy env load --non-secrets ` | Load .env file, marking specific keys as non-secrets | +| `deno deploy database provision --kind ` | Provision a new database | +| `deno deploy database assign --app ` | Assign database to an app | +| `deno deploy logs` | View deployment logs | +| `deno run --tunnel -A ` | Start local tunnel | +| `deno task --tunnel ` | Run task with tunnel | + +## Edge Runtime Notes + +Deno Deploy runs in one or many regions (globally distributed). Keep in mind: + +- **Environment variables** - Must be set via `deno deploy env`, not .env files + at runtime +- **Global distribution** - Code runs at the region closest to users +- **Cold starts** - First request after idle may be slightly slower + +## Additional References + +- [Authentication](references/AUTHENTICATION.md) - Interactive and CI/CD + authentication +- [Databases](references/DATABASES.md) - Database provisioning and connections +- [Deno KV](references/DENO_KV.md) - Key-value storage API and examples +- [Domains](references/DOMAINS.md) - Custom domains and SSL certificates +- [Frameworks](references/FRAMEWORKS.md) - Framework-specific deployment guides +- [Organizations](references/ORGANIZATIONS.md) - Managing orgs and members +- [Runtime](references/RUNTIME.md) - Lifecycle, cold starts, and limitations +- [Troubleshooting](references/TROUBLESHOOTING.md) - Common issues and solutions + +## Documentation + +- Official docs: https://docs.deno.com/deploy/ +- CLI reference: https://docs.deno.com/runtime/reference/cli/deploy/ +- Databases: https://docs.deno.com/deploy/reference/databases/ +- Deno KV: https://docs.deno.com/deploy/reference/deno_kv/ +- Domains: https://docs.deno.com/deploy/reference/domains/ +- Environment variables & contexts: + https://docs.deno.com/deploy/reference/env_vars_and_contexts/ +- Organizations: https://docs.deno.com/deploy/reference/organizations/ +- Runtime: https://docs.deno.com/deploy/reference/runtime/ +- Tunnel: https://docs.deno.com/deploy/reference/tunnel/ diff --git a/plugins/deno/agent/skills/deno-deploy/references/AUTHENTICATION.md b/plugins/deno/agent/skills/deno-deploy/references/AUTHENTICATION.md new file mode 100644 index 00000000..4fd9e7fb --- /dev/null +++ b/plugins/deno/agent/skills/deno-deploy/references/AUTHENTICATION.md @@ -0,0 +1,185 @@ +# Deno Deploy Authentication + +## Interactive Authentication (Default) + +The first time you run `deno deploy`, it will open a browser for authentication: + +```bash +deno deploy +# Opens: https://console.deno.com/auth?code=XXXX-XXXX +``` + +**Important - Browser Device Authorization Flow:** + +- The CLI opens your browser and waits for you to complete authentication +- You must complete the authorization in your browser before the CLI can + continue +- The CLI will not proceed automatically - it waits until you finish +- Credentials are stored in your system keyring after successful auth + +**Note:** When running `deno deploy` commands that require authentication, the +user must complete the browser authorization before the deployment can proceed. + +## Non-Interactive Authentication (CI/CD & Automation) + +To deploy without browser interaction (for CI/CD pipelines or automated +workflows): + +### 1. Create a Deploy Token + +1. Visit https://console.deno.com/account/access-tokens +2. Click "New Access Token" +3. Give it a descriptive name (e.g., "GitHub Actions CI") +4. Copy the token immediately (shown only once) + +### 2. Use the Token + +```bash +# Option 1: Environment variable (recommended for CI/CD) +export DENO_DEPLOY_TOKEN="your-token-here" +deno deploy --prod + +# Option 2: Inline flag (for one-off commands) +deno deploy --token "your-token-here" --prod +``` + +### 3. GitHub Actions Example + +```yaml +- name: Deploy to Deno Deploy + env: + DENO_DEPLOY_TOKEN: ${{ secrets.DENO_DEPLOY_TOKEN }} + run: deno deploy --prod +``` + +If the app doesn't exist yet, create it first in CI/CD using non-interactive +flags: + +```yaml +- name: Create and deploy app + env: + DENO_DEPLOY_TOKEN: ${{ secrets.DENO_DEPLOY_TOKEN }} + run: | + deno deploy create \ + --org my-org --app my-app \ + --source local \ + --runtime-mode dynamic --entrypoint main.ts \ + --build-timeout 10 --build-memory-limit 2048 --region us +``` + +After the app is created, subsequent deploys only need `deno deploy --prod`. + +**Tip:** For fully automated deploys without browser prompts, ensure a Deno +Deploy access token is set up. Create one at +https://console.deno.com/account/access-tokens, then set it as the +`DENO_DEPLOY_TOKEN` environment variable. + +## Finding Your Organization Name + +The Deno Deploy CLI requires an organization context for most operations. To +find your org name: + +1. Visit https://console.deno.com +2. Your org is in the URL: `console.deno.com/YOUR-ORG-NAME` + +**Note:** Commands like `deno deploy orgs` and `deno deploy switch` require an +existing org context to work - this is a CLI limitation. Always find your org +name from the console URL first. + +## Setting Up Your First App + +**Before creating:** Check if an app already exists: + +```bash +cat deno.json | grep -A5 '"deploy"' +``` + +If no deploy config exists, you need to create the app first. Apps must be +created before they can be deployed to. + +**Interactive creation** (opens a browser): + +```bash +deno deploy create --org your-org-name +``` + +This opens a browser to create the app. **Important:** + +- Complete the app creation in your browser +- The CLI waits until you finish - it won't proceed automatically +- The app name becomes your URL: `.deno.dev` + +**Non-interactive creation** (for AI agents and CI/CD — no browser needed): + +```bash +deno deploy create \ + --org your-org-name \ + --app your-app-name \ + --source local \ + --runtime-mode dynamic \ + --entrypoint main.ts \ + --build-timeout 5 \ + --build-memory-limit 1024 \ + --region us +``` + +This creates the app and does the initial deploy in one step. No browser +interaction required. See the main skill doc for the full list of `create` +flags. + +**Verifying Success:** After completion, verify by checking deno.json: + +```bash +cat deno.json | grep -A5 '"deploy"' +``` + +You should see: + +```json +"deploy": { + "org": "your-org-name", + "app": "your-app-name" +} +``` + +After this, subsequent deploys only need: + +```bash +deno deploy --prod +``` + +## Interactive Commands + +Some `deno deploy` commands are interactive and cannot be run through automated +tools. + +### Switching Organizations/Apps + +```bash +deno deploy switch +``` + +This opens an interactive menu to select org and app. + +**Alternative - Use Explicit Flags:** + +Instead of interactive selection, specify org/app directly: + +```bash +deno deploy --org your-org-name --app your-app-name --prod +``` + +This bypasses the interactive flow. + +## Commands That Fail Without Org Context + +These commands will error if no org is configured: + +- `deno deploy` (without --org flag) +- `deno deploy orgs` +- `deno deploy switch` +- `deno deploy env list` +- `deno deploy logs` + +Always ensure org context is set via deno.json or --org flag before running +these commands. diff --git a/plugins/deno/agent/skills/deno-deploy/references/DATABASES.md b/plugins/deno/agent/skills/deno-deploy/references/DATABASES.md new file mode 100644 index 00000000..45bb89e0 --- /dev/null +++ b/plugins/deno/agent/skills/deno-deploy/references/DATABASES.md @@ -0,0 +1,159 @@ +# Databases on Deno Deploy + +## Overview + +Deno Deploy provides built-in database support with automatic environment +isolation. You don't need to manage connection strings or worry about mixing +production and development data. + +## Available Database Engines + +| Engine | Description | +| -------------- | -------------------------------------------------------------------- | +| **Deno KV** | Fast, globally distributed key-value store hosted by Deno | +| **PostgreSQL** | Connect your own PostgreSQL or provision managed Postgres via Prisma | + +## Key Concept: Timelines + +Deno Deploy automatically creates **isolated databases for each environment**: + +- **Production:** `{app-id}-production` +- **Git branches:** `{app-id}--{branch-name}` +- **Preview deployments:** `{app-id}-preview` + +This means your preview deployments won't accidentally modify production data. + +## Database CLI Commands + +Use `deno deploy database` to manage databases from the command line. + +### List Databases + +```bash +# List all databases in your organization +deno deploy database list + +# Search for databases by name +deno deploy database list my-prefix +``` + +### Provision a Database + +Create a new managed database: + +```bash +# Provision a new Deno KV database +deno deploy database provision my-database --kind denokv + +# Provision a new Prisma PostgreSQL database (requires --region) +deno deploy database provision my-database --kind prisma --region us-east-1 +``` + +### Link an External Database + +Link an existing external postgres database by providing a connection string: + +```bash +deno deploy database link my-database "postgres://user:pass@host:5432/db" +``` + +### Assign / Detach + +Connect or disconnect a database from an app: + +```bash +# Assign a database to an app +deno deploy database assign my-database --app my-app + +# Detach a database from an app +deno deploy database detach my-database --app my-app +``` + +Deno Deploy creates separate databases for each timeline automatically. + +### Query a Database + +Run queries directly from the CLI: + +```bash +deno deploy database query my-database production "SELECT * FROM users LIMIT 10" +``` + +The second argument is the timeline name (e.g., `production`, `preview`, or a +branch name), which can be found in the output of `deno deploy database list`. + +### Delete a Database + +```bash +deno deploy database delete my-database +``` + +## Connecting in Code + +### Deno KV + +No configuration needed - just call `Deno.openKv()`: + +```typescript +const kv = await Deno.openKv(); + +// Deno Deploy automatically connects to the right database +// based on your current environment (production, preview, etc.) +``` + +### PostgreSQL + +Deno Deploy injects standard environment variables that most PostgreSQL +libraries detect automatically: + +- `DATABASE_URL` - Full connection string +- `PGHOST`, `PGPORT`, `PGDATABASE`, `PGUSER`, `PGPASSWORD` - Individual + components + +```typescript +// Recommended: npm:pg (best PostgreSQL driver for Deno Deploy) +import pg from "npm:pg"; +const pool = new pg.Pool(); // Reads DATABASE_URL from environment automatically +const { rows } = await pool.query("SELECT * FROM users"); +``` + +## Local Development + +### With Tunnel + +Use `--tunnel` to connect your local dev server to your hosted development +database: + +```bash +deno task --tunnel dev +``` + +This gives you access to the same database environment variables locally. + +### Without Tunnel + +- **Deno KV:** Data stays in memory during local development +- **PostgreSQL:** Point to a local PostgreSQL instance or use the tunnel + +## Migrations + +Deno Deploy supports pre-deploy commands that run before each deployment. Use +these for database migrations: + +```json +{ + "deploy": { + "preDeploy": ["deno task db:migrate"] + } +} +``` + +## Sharing Databases + +Multiple apps can share the same database instance. Each app gets its own +isolated databases per timeline, even when sharing. + +## Documentation + +- Databases overview: https://docs.deno.com/deploy/reference/databases/ +- Deno KV reference: https://docs.deno.com/deploy/reference/deno_kv/ diff --git a/plugins/deno/agent/skills/deno-deploy/references/DENO_KV.md b/plugins/deno/agent/skills/deno-deploy/references/DENO_KV.md new file mode 100644 index 00000000..309144cd --- /dev/null +++ b/plugins/deno/agent/skills/deno-deploy/references/DENO_KV.md @@ -0,0 +1,153 @@ +# Deno KV + +## What is Deno KV? + +Deno KV is a key-value database built into Deno. On Deno Deploy, it's a fast, +globally distributed store that requires no setup or configuration. + +## Quick Start + +```typescript +// Open the KV store (auto-connects on Deno Deploy) +const kv = await Deno.openKv(); + +// Store a value +await kv.set(["users", "alice"], { name: "Alice", email: "alice@example.com" }); + +// Retrieve a value +const result = await kv.get(["users", "alice"]); +console.log(result.value); // { name: "Alice", email: "alice@example.com" } + +// Delete a value +await kv.delete(["users", "alice"]); +``` + +## Keys + +Keys are arrays of "key parts" that form a hierarchy: + + +```typescript +// Simple key +["settings"] + +// Hierarchical keys +["users", "alice"] +["users", "bob"] +["posts", "2024", "01", "my-post"] +``` + +Key parts can be strings, numbers, booleans, Uint8Array, or bigints. + +## Basic Operations + +### Get + +```typescript +const result = await kv.get(["users", "alice"]); +if (result.value) { + console.log(result.value.name); +} +``` + +### Set + +```typescript +await kv.set(["users", "alice"], { name: "Alice" }); + +// With expiration (in milliseconds) +await kv.set(["sessions", sessionId], data, { expireIn: 3600000 }); // 1 hour +``` + +### Delete + +```typescript +await kv.delete(["users", "alice"]); +``` + +### List + +```typescript +// List all users +const users = kv.list({ prefix: ["users"] }); +for await (const entry of users) { + console.log(entry.key, entry.value); +} + +// With limit +const firstTen = kv.list({ prefix: ["users"] }, { limit: 10 }); +``` + +## Atomic Transactions + +Perform multiple operations atomically (all succeed or all fail): + +```typescript +// Transfer credits between users +const alice = await kv.get(["credits", "alice"]); +const bob = await kv.get(["credits", "bob"]); + +const result = await kv.atomic() + .check(alice) // Ensure alice hasn't changed + .check(bob) // Ensure bob hasn't changed + .set(["credits", "alice"], alice.value! - 100) + .set(["credits", "bob"], bob.value! + 100) + .commit(); + +if (!result.ok) { + console.log("Transaction failed - data was modified"); +} +``` + +## Example: Request Counter + +```typescript +const kv = await Deno.openKv(); + +Deno.serve(async () => { + // Increment counter atomically + const key = ["requests"]; + + let result = { ok: false }; + while (!result.ok) { + const current = await kv.get(key); + const newCount = (current.value ?? 0) + 1; + + result = await kv.atomic() + .check(current) + .set(key, newCount) + .commit(); + } + + const count = (await kv.get(key)).value; + return new Response(`Requests: ${count}`); +}); +``` + +## Data Location + +On Deno Deploy, KV data is replicated across at least three data centers in +Northern Virginia (us-east-4). Cross-region replication is not currently +available. + +## Local Development + +When running locally with `deno run`, KV data is stored in memory by default. +For persistent local storage: + +```typescript +// Persist to a local file +const kv = await Deno.openKv("./my-database.sqlite"); +``` + +## Important Notes + +- **Deletion is permanent** - Deleting a KV instance removes all data with no + recovery +- **Back up important data** before deleting instances +- **No cross-region replication** yet - data lives in us-east-4 + +## Documentation + +- Deno KV on Deploy: https://docs.deno.com/deploy/reference/deno_kv/ +- Deno KV API: https://docs.deno.com/api/deno/~/Deno.Kv diff --git a/plugins/deno/agent/skills/deno-deploy/references/DOMAINS.md b/plugins/deno/agent/skills/deno-deploy/references/DOMAINS.md new file mode 100644 index 00000000..bf0351e9 --- /dev/null +++ b/plugins/deno/agent/skills/deno-deploy/references/DOMAINS.md @@ -0,0 +1,93 @@ +# Custom Domains + +## Default Domain + +Every organization gets a default domain: `your-org.deno.net` + +Apps are accessible at: `your-app.deno.dev` + +## Adding a Custom Domain + +1. Go to your organization's domains page in the Deno Deploy dashboard +2. Click "Add Domain" +3. Enter your domain (e.g., `example.com` or `*.example.com` for wildcards) +4. Click "Add Domain" to see DNS configuration + +## DNS Configuration + +You have three options for DNS setup: + +### Option 1: ANAME/ALIAS (Recommended) + +Best option if your registrar supports ANAME or ALIAS records. + +| Record Type | Name | Value | +| ----------- | ----------------- | ----------------------- | +| ANAME/ALIAS | `@` | `.deno.dev` | +| CNAME | `_acme-challenge` | (provided in dashboard) | + +### Option 2: CNAME + +Works for subdomains (like `api.example.com`) but **not for apex domains** (like +`example.com`). + +| Record Type | Name | Value | +| ----------- | --------------------- | ----------------------- | +| CNAME | `api` | `.deno.dev` | +| CNAME | `_acme-challenge.api` | (provided in dashboard) | + +### Option 3: A Record + +Most compatible, works with any registrar. + +| Record Type | Name | Value | +| ----------- | ----------------- | -------------------------- | +| A | `@` | (IP provided in dashboard) | +| CNAME | `_acme-challenge` | (provided in dashboard) | + +**Note:** IPv6 is not supported with the A record method. + +## Cloudflare Users + +If using Cloudflare, **disable proxying** (turn off the orange cloud) on the +`_acme-challenge` CNAME record. Proxying prevents certificate verification from +completing. + +## SSL/TLS Certificates + +### Automatic Certificates (Recommended) + +After DNS verification completes: + +1. Click "Provision Certificate" in the dashboard +2. Let's Encrypt generates your certificate +3. Certificates renew automatically + +### Bring Your Own Certificate + +If you need a specific certificate: + +1. Upload your PEM-formatted certificate file +2. Upload your private key file +3. **You must manage renewal** - notifications arrive 14 days before expiration + +**Warning:** Expired certificates cause your domain to stop working. + +## Assigning Domains to Apps + +1. Go to organization domains page +2. Find your domain and click to edit +3. Assign it to an application +4. Remove assignments from app settings if needed + +## Troubleshooting + +| Issue | Solution | +| --------------------------- | --------------------------------------------------------- | +| Verification stuck | Check DNS propagation (can take up to 48 hours) | +| Certificate won't provision | Ensure `_acme-challenge` CNAME is correct and not proxied | +| IPv6 not working | Use ANAME/ALIAS or CNAME instead of A record | + +## Documentation + +- Domains reference: https://docs.deno.com/deploy/reference/domains/ diff --git a/plugins/deno/agent/skills/deno-deploy/references/FRAMEWORKS.md b/plugins/deno/agent/skills/deno-deploy/references/FRAMEWORKS.md new file mode 100644 index 00000000..e7cb31a1 --- /dev/null +++ b/plugins/deno/agent/skills/deno-deploy/references/FRAMEWORKS.md @@ -0,0 +1,215 @@ +# Framework-Specific Deployment + +Deno Deploy supports multiple frameworks. The CLI auto-detects your framework +and configures the build appropriately. + +## Framework Detection + +| Framework | Detection Files | Build Command | Notes | +| -------------- | ------------------------------------- | ------------------------------------ | --------------------------------- | +| **Fresh** | `islands/`, `fresh.config.ts` | `deno task build` | Deno-native, island architecture | +| **Astro** | `astro.config.mjs`, `astro.config.ts` | `npm run build` or `deno task build` | Static or SSR | +| **Next.js** | `next.config.js`, `next.config.mjs` | `npm run build` | Requires `nodeModulesDir: "auto"` | +| **Nuxt** | `nuxt.config.ts` | `npm run build` | Vue SSR framework | +| **Remix** | `remix.config.js` | `npm run build` | React SSR framework | +| **SolidStart** | `app.config.ts` with solid | `npm run build` | SolidJS SSR | +| **SvelteKit** | `svelte.config.js` | `npm run build` | Svelte SSR framework | +| **Lume** | `_config.ts` with lume import | `deno task build` | Deno-native static site | + +## Framework Presets for `deno deploy create` + +When creating an app with `deno deploy create` in non-interactive mode, you can +specify `--framework-preset` to auto-configure build commands and runtime +settings. The available presets are: `Fresh`, `Next`, `Remix`, `Astro`, +`SvelteKit`, `Nuxt`, `Lume`, `SolidStart`. + +When a preset is specified, you can omit `--install-command`, `--build-command`, +`--pre-deploy-command`, and `--runtime-mode` — they are inferred from the +preset. + +If you don't specify a preset, the CLI still auto-detects your framework from +the project files. Use `--do-not-use-detected-build-config` to skip +auto-detection and specify everything manually. + +## Detect Framework Script + +```bash +if [ -d "islands" ] || [ -f "fresh.config.ts" ]; then echo "Framework: Fresh"; \ +elif [ -f "astro.config.mjs" ] || [ -f "astro.config.ts" ]; then echo "Framework: Astro"; \ +elif [ -f "next.config.js" ] || [ -f "next.config.mjs" ]; then echo "Framework: Next.js"; \ +elif [ -f "nuxt.config.ts" ]; then echo "Framework: Nuxt"; \ +elif [ -f "remix.config.js" ]; then echo "Framework: Remix"; \ +elif [ -f "svelte.config.js" ]; then echo "Framework: SvelteKit"; \ +elif [ -f "_config.ts" ]; then echo "Framework: Lume (check imports)"; \ +else echo "Framework: Custom/Unknown"; fi +``` + +## Fresh (Deno-Native) + +```bash +deno task build +deno deploy --prod +``` + +## Fresh + PostgreSQL + +When a Fresh app uses PostgreSQL (e.g., `await initDb()` at startup), you must +provision the database **before** the app can successfully warm up. The Fresh +auto-detection preset also has a known issue, so use manual build config. + +**Complete deployment sequence:** + +```bash +# 1. Create the app with --no-wait (warmup will fail without a database — that's expected) +deno deploy create \ + --org --app \ + --source local \ + --do-not-use-detected-build-config \ + --install-command "deno install" \ + --build-command "deno task build" \ + --pre-deploy-command "echo ready" \ + --runtime-mode dynamic --entrypoint main.ts \ + --build-timeout 5 --build-memory-limit 1024 --region us \ + --no-wait + +# 2. Provision a PostgreSQL database +deno deploy database provision my-db --kind prisma --region us-east-1 + +# 3. Assign it to the app (this injects DATABASE_URL, PGHOST, etc.) +deno deploy database assign my-db --app + +# 4. Redeploy — now the database exists, so warmup succeeds +deno deploy --prod +``` + +**Why this order matters:** + +- Fresh + PostgreSQL apps typically call `await initDb()` in `main.ts`, which + runs during warmup +- If no database is assigned, the connection fails and the deploy is marked as + failed +- Using `--no-wait` on the first deploy lets you continue to the database setup + without blocking + +**Why `--do-not-use-detected-build-config`:** + +- The Fresh auto-detection and `--framework-preset fresh` can fail with an API + error +- Manual build config is more reliable — see + [Troubleshooting](TROUBLESHOOTING.md#fresh-auto-detection--preset-fails) + +## Astro + +```bash +# If using npm +npm run build +deno deploy --prod + +# If using Deno tasks +deno task build +deno deploy --prod +``` + +## Next.js + +Next.js requires Node.js compatibility mode: + +1. Ensure `deno.json` has: + ```json + { + "nodeModulesDir": "auto" + } + ``` + +2. Build and deploy: + ```bash + npm install + npm run build + deno deploy --prod --allow-node-modules + ``` + +## Nuxt / Remix / SvelteKit / SolidStart + +These npm-based frameworks follow a similar pattern: + +```bash +npm install +npm run build +deno deploy --prod +``` + +If you encounter issues with node_modules: + +```bash +deno deploy --prod --allow-node-modules +``` + +## Lume (Static Sites) + +```bash +deno task build +deno deploy --prod +``` + +## Custom / No Framework + +For custom servers or apps without a recognized framework: + +1. Ensure you have an entrypoint (e.g., `main.ts`, `server.ts`) +2. Deploy directly: + ```bash + deno deploy --entrypoint main.ts --prod + ``` + +## Static Site Deployment + +For static sites (Lume, Vite builds, etc.), you have two options: + +### Option 1: Direct Directory Deployment + +Point Deno Deploy at your built directory. Configure in `deno.json`: + +```json +{ + "deploy": { + "entrypoint": "main.ts", + "include": ["_site"] + } +} +``` + +### Option 2: Custom Server Wrapper + +Only needed if you want custom routing, headers, or logic: + +```typescript +// serve.ts +import { serveDir } from "jsr:@std/http/file-server"; + +Deno.serve((req) => + serveDir(req, { + fsRoot: "_site", + quiet: true, + }) +); +``` + +Then deploy with: + +```bash +deno deploy --entrypoint serve.ts --prod +``` + +## Cloud Integrations + +### AWS Integration + +```bash +deno deploy setup-aws --org my-org --app my-app +``` + +### GCP Integration + +```bash +deno deploy setup-gcp --org my-org --app my-app +``` diff --git a/plugins/deno/agent/skills/deno-deploy/references/ORGANIZATIONS.md b/plugins/deno/agent/skills/deno-deploy/references/ORGANIZATIONS.md new file mode 100644 index 00000000..cdebac30 --- /dev/null +++ b/plugins/deno/agent/skills/deno-deploy/references/ORGANIZATIONS.md @@ -0,0 +1,86 @@ +# Organizations + +## What is an Organization? + +In Deno Deploy, an organization is a group where users collectively own apps and +domains. Every user belongs to an organization - all resources (apps, domains, +environment variables) exist at the organization level. + +Each organization has: + +- **Name:** Displayed in the dashboard +- **Slug:** Part of your default domain (e.g., `acme-inc.deno.net`) + +**Important:** The slug cannot be changed after creation. + +## Creating an Organization + +Organizations are created automatically during Deno Deploy signup: + +1. Visit https://console.deno.com +2. Sign in with GitHub +3. Create your organization as part of setup + +## Finding Your Organization + +Your org name appears in the console URL: + +``` +https://console.deno.com/YOUR-ORG-NAME +``` + +Use this for CLI commands: + +```bash +deno deploy create --org YOUR-ORG-NAME +deno deploy --org YOUR-ORG-NAME --prod +``` + +## Managing Members + +### Inviting Users + +1. Go to organization settings in the dashboard +2. Click "+ Invite User" +3. Enter the person's GitHub username (e.g., `ry`) +4. Optionally add their email address +5. Send the invitation + +The invitee receives an email with a link to accept. + +### Removing Members + +1. Go to organization settings +2. Find the user in the members table +3. Click remove and confirm + +### Canceling Invitations + +Pending invitations can be cancelled before the person accepts. + +## Permissions + +Currently, **all members have owner permissions**. Every member can: + +- Invite and remove other members +- Create and delete apps +- Manage domains +- Configure environment variables +- Deploy to production + +There is no tiered permission system yet. + +## Organization Deletion + +Organizations **cannot be deleted through the dashboard**. Contact Deno support +if you need to delete an organization. + +## Best Practices + +- **Choose your slug carefully** - it's permanent and visible in URLs +- **Limit membership** - since all members have full access +- **Use descriptive app names** - they become part of URLs too + +## Documentation + +- Organizations reference: https://docs.deno.com/deploy/reference/organizations/ diff --git a/plugins/deno/agent/skills/deno-deploy/references/RUNTIME.md b/plugins/deno/agent/skills/deno-deploy/references/RUNTIME.md new file mode 100644 index 00000000..4077d1c3 --- /dev/null +++ b/plugins/deno/agent/skills/deno-deploy/references/RUNTIME.md @@ -0,0 +1,103 @@ +# Deno Deploy Runtime + +## Overview + +Deno Deploy uses the standard Deno runtime. You can use JSR and NPM packages, +filesystem operations, network requests, subprocesses, and FFI/native addons. + +## Current Environment + +- **Runtime:** Deno 2.5.0 +- **Platform:** Linux (x64 or ARM64) +- **Permissions:** All permissions enabled automatically (`--allow-all`) + +**Note:** Custom Deno flags cannot be passed to the runtime. + +## Serverless Lifecycle + +Understanding how your app starts and stops is important for building reliable +applications. + +### Startup + +Your application starts when a request arrives. If your app crashes before the +HTTP server starts, requests return a 502 error. + +**Tip:** Keep startup fast by: + +- Reducing dependencies +- Using dynamic imports for rarely-used code +- Avoiding network requests during startup + +### Idle Shutdown + +After 5-10 minutes without requests: + +1. The system sends a `SIGINT` signal +2. Your app has 5 seconds to shut down gracefully +3. If still running, `SIGKILL` terminates it + +```typescript +// Handle graceful shutdown +Deno.addSignalListener("SIGINT", () => { + console.log("Shutting down..."); + // Clean up resources, close connections + Deno.exit(0); +}); +``` + +### Eviction + +Even during active traffic, instances may be terminated due to: + +- Infrastructure updates +- Resource constraints + +The system redirects traffic first, then signals shutdown. **Long-running +connections should expect reconnections.** + +## Cold Start Performance + +Cold starts typically complete: + +- **~100ms** for simple "hello world" apps +- **A few hundred ms** for larger applications + +Deno Deploy optimizes cold starts using: + +- Pre-provisioned microVMs +- Early TCP connection setup +- File system warmup + +### Minimizing Cold Start Time + +```typescript +// BAD: Top-level network request delays startup +const config = await fetch("https://api.example.com/config").then((r) => + r.json() +); + +// GOOD: Lazy load on first request +let config: Config | null = null; +async function getConfig() { + if (!config) { + config = await fetch("https://api.example.com/config").then((r) => + r.json() + ); + } + return config; +} +``` + +## Limitations + +| Feature | Status | +| ----------------------------- | ------------------------ | +| Custom Deno flags | Not supported | +| Persistent filesystem | Use Deno KV instead | +| Long-running background tasks | May be interrupted | +| System tools | Available but may change | + +## Documentation + +- Runtime reference: https://docs.deno.com/deploy/reference/runtime/ diff --git a/plugins/deno/agent/skills/deno-deploy/references/TROUBLESHOOTING.md b/plugins/deno/agent/skills/deno-deploy/references/TROUBLESHOOTING.md new file mode 100644 index 00000000..066f2947 --- /dev/null +++ b/plugins/deno/agent/skills/deno-deploy/references/TROUBLESHOOTING.md @@ -0,0 +1,191 @@ +# Deno Deploy Troubleshooting + +## First Step: Use `--help` + +Before debugging a failed command, run `--help` to confirm the flags you're +using actually exist and are spelled correctly: + +```bash +deno deploy create --help +deno deploy env --help +deno deploy database --help +``` + +Exit code 2 almost always means a flag is missing or invalid — `--help` will +show you exactly what's required. + +## Common Errors + +### "No organization was selected" + +This error occurs because the CLI needs an organization context. Unfortunately, +commands like `deno deploy orgs` also fail without this context. + +**Solution:** + +1. **Find your org name manually:** Visit https://console.deno.com - your org is + in the URL path (e.g., `console.deno.com/donjo` means org is `donjo`) + +2. **Specify org explicitly:** + ```bash + deno deploy --org your-org-name --prod + ``` + +3. **Or create an app with org:** + ```bash + deno deploy create --org your-org-name + # Complete the browser flow when prompted + ``` + +If you see this error, the user needs to provide their organization name from +the console URL. + +### "No entrypoint found" + +Specify your entry file: + +```bash +deno deploy --entrypoint main.ts --prod +``` + +Or add to `deno.json`: + +```json +{ + "deploy": { + "entrypoint": "main.ts" + } +} +``` + +### "authorization required" + +Token expired or missing. Options: + +- Re-authenticate interactively (browser flow) +- Set up a CI/CD token via `DENO_DEPLOY_TOKEN` environment variable +- Create a new token at https://console.deno.com/account/access-tokens + +### "Minimum Deno version required" + +User needs to upgrade Deno: + +```bash +deno upgrade +``` + +The `deno deploy` command requires Deno >= 2.4.2. + +### Fresh "Build required" Error + +Fresh 2.0 requires building before deployment: + +```bash +deno task build +deno deploy --prod +``` + +### Environment Variable Errors + +Check what's currently set: + +```bash +deno deploy env list +``` + +Add missing variables: + +```bash +deno deploy env add MISSING_VAR "value" +``` + +### Warmup Failure After Deploy + +The build succeeds but the deploy fails with a warmup error or exit code 1. This +usually means the app crashes on startup. + +**Most common cause:** The app connects to a database at startup (e.g., +`await initDb()` in `main.ts`), but no database has been provisioned or assigned +yet. + +**Solution:** + +1. Provision and assign the database: + ```bash + deno deploy database provision my-db --kind prisma --region us-east-1 + deno deploy database assign my-db --app + ``` + +2. Redeploy: + ```bash + deno deploy --prod + ``` + +For a complete walkthrough, see the +[Fresh + PostgreSQL recipe](FRAMEWORKS.md#fresh--postgresql). + +### Fresh Auto-Detection / Preset Fails + +When the CLI auto-detects Fresh or you use `--framework-preset fresh`, the +deploy may fail with an API error. This is a known issue. + +**Workaround:** Use `--do-not-use-detected-build-config` and specify all build +commands manually: + +```bash +deno deploy create \ + --org --app \ + --source local \ + --do-not-use-detected-build-config \ + --install-command "deno install" \ + --build-command "deno task build" \ + --pre-deploy-command "echo ready" \ + --runtime-mode dynamic --entrypoint main.ts \ + --build-timeout 5 --build-memory-limit 1024 --region us +``` + +## Error Response Table + +| Error | Cause | Solution | +| ------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------ | +| "No organization was selected" | No org in config | Get org name from console URL, use `--org` flag | +| "No entrypoint found" | Can't find main file | Use `--entrypoint` flag or set in deno.json | +| "authorization required" | Token expired/missing | Re-authenticate or set `DENO_DEPLOY_TOKEN` | +| "Minimum Deno version required" | Deno too old | Run `deno upgrade` | +| Exit code 2 (usage error) | Missing or invalid flags | Run `deno deploy create --help` to see required flags | +| Warmup failure (exit code 1) | App crashes on startup | Check for missing database or env vars — see [Warmup Failure](#warmup-failure-after-deploy) | +| Fresh preset API error | Auto-detection bug | Use `--do-not-use-detected-build-config` — see [Fresh workaround](#fresh-auto-detection--preset-fails) | + +## Verifying Deployment Success + +The CLI output can be verbose. Look for these indicators of success: + +- A URL containing `.deno.dev` or `.deno.net` - this is your live deployment +- A console URL like `https://console.deno.com///builds/` +- The command exits with code 0 (no error) + +After deployment, confirm success by extracting the production URL from the +output. The format is typically: `https://..deno.net` or +`https://.deno.dev` + +## Commands That Require Org Context + +These commands will error if no org is configured - do not try them to +"discover" orgs: + +- `deno deploy` (without --org flag) +- `deno deploy orgs` +- `deno deploy switch` +- `deno deploy env list` +- `deno deploy logs` + +## Environment Variable Contexts + +Variables can apply to different environments: + +```bash +# Set which contexts a variable applies to +deno deploy env update-contexts API_KEY Production Preview +``` + +Available contexts: `Production`, `Preview`, `Local`, `Build` diff --git a/plugins/deno/agent/skills/deno-frontend/SKILL.md b/plugins/deno/agent/skills/deno-frontend/SKILL.md new file mode 100644 index 00000000..3a83dd34 --- /dev/null +++ b/plugins/deno/agent/skills/deno-frontend/SKILL.md @@ -0,0 +1,89 @@ +--- +name: deno-frontend +description: Use when building a web frontend with Deno — running React, Vite, + Astro, SvelteKit, Next.js, Nuxt or other npm frameworks under Deno, or working + with Fresh, Deno's own island-architecture framework. Covers which path to + pick, Fresh 2.x routes, handlers, islands, Preact signals, Tailwind, and Fresh + 1.x to 2.x migration. +license: MIT +metadata: + author: denoland + version: "3.0" +--- +# Frontend development with Deno + +Two paths. Pick by what the project already uses. + +## Regular npm frameworks — the usual choice + +Deno runs the normal frontend ecosystem: React, Vue, Svelte, Solid, Vite, Astro, +Next.js, Nuxt, SvelteKit, Remix, SolidStart. Nothing needs to be ported, and +there is no Deno-specific way to write them. + +```bash +deno create vite my-app # or astro, next, nuxt, svelte… +cd my-app +deno install +deno task dev +``` + +`deno create` is `npm create`. `deno install` reads `package.json`. +`deno task @@ -209,6 +209,8 @@ function resetErrors() { ``` +By default, `validate()` throws a `FormValidationException` when validation fails. Pass `{ silent: true }` when you want it to return `false` instead. Use `clear()` to remove validation errors. + ## Form in a modal Use `#footer="{ close }"` scoped slot for cancel/submit actions. Wrap the modal body in `UForm` with a `type="submit"` button in the footer so validation runs on submit. diff --git a/plugins/nuxt-ui/.agents/skills/nuxt-ui/references/layouts/chat.md b/plugins/nuxt-ui/.agents/skills/nuxt-ui/references/layouts/chat.md index 5ba3b6c8..070f4abc 100644 --- a/plugins/nuxt-ui/.agents/skills/nuxt-ui/references/layouts/chat.md +++ b/plugins/nuxt-ui/.agents/skills/nuxt-ui/references/layouts/chat.md @@ -200,7 +200,7 @@ function onSubmit() { - `UChatMessage` — individual bubble. Props: `message`, `side` (`'left'`/`'right'`). - `UChatReasoning` — collapsible reasoning block. Auto-opens during streaming, auto-closes when done. Use `isPartStreaming(part)` from `@nuxt/ui/utils/ai`. - `UChatTool` — tool invocation status. Use `isToolStreaming(part)`. Variants: `'inline'` (default), `'card'`. -- `UChatPrompt` — enhanced textarea. Accepts all Textarea props + `error` prop. +- `UChatPrompt` — enhanced textarea for chat. Its typed API exposes a selected subset of `UTextarea` props, forwards additional attributes to the underlying textarea, and adds chat-specific props such as `error` and `submitOnEnter`. - `UChatPromptSubmit` — submit button with automatic status handling (send/stop/reload). - `UChatPalette` — layout wrapper for chat inside overlays. diff --git a/plugins/nuxt-ui/agent/skills/nuxt-ui/references/guidelines/component-selection.md b/plugins/nuxt-ui/agent/skills/nuxt-ui/references/guidelines/component-selection.md index c2d1ce14..b34c1ab9 100644 --- a/plugins/nuxt-ui/agent/skills/nuxt-ui/references/guidelines/component-selection.md +++ b/plugins/nuxt-ui/agent/skills/nuxt-ui/references/guidelines/component-selection.md @@ -16,7 +16,7 @@ Decision matrices for choosing the right component. When in doubt, use the MCP ` - Use `UModal` for destructive confirmations ("Are you sure you want to delete?") - Use `USlideover` for detail views in dashboards (email preview, user profile) - Use `UDrawer` for mobile navigation or action sheets -- Modal and Slideover support `mode="drawer"` for automatic mobile drawer behavior +- Use `UDashboardSidebar` with `mode="drawer"` for a drawer-based mobile menu; `UModal` and `USlideover` don't expose a `mode` prop - For programmatic overlays, use `useOverlay()` instead of `v-model:open` - Never put interactive content (buttons, links) inside `UTooltip` diff --git a/plugins/nuxt-ui/agent/skills/nuxt-ui/references/guidelines/conventions.md b/plugins/nuxt-ui/agent/skills/nuxt-ui/references/guidelines/conventions.md index c1aa29eb..c067c707 100644 --- a/plugins/nuxt-ui/agent/skills/nuxt-ui/references/guidelines/conventions.md +++ b/plugins/nuxt-ui/agent/skills/nuxt-ui/references/guidelines/conventions.md @@ -172,7 +172,8 @@ const items = [ ] ``` -Components supporting nested arrays: `UDropdownMenu`, `UContextMenu`, `UCommandPalette`, `UNavigationMenu`. +Components supporting nested arrays: `UDropdownMenu`, `UContextMenu`, `UNavigationMenu`. +`UCommandPalette` uses a `groups` prop instead, with an `items` array on each group. ## Composables diff --git a/plugins/nuxt-ui/agent/skills/nuxt-ui/references/guidelines/forms.md b/plugins/nuxt-ui/agent/skills/nuxt-ui/references/guidelines/forms.md index 2a3eda14..5fd91f19 100644 --- a/plugins/nuxt-ui/agent/skills/nuxt-ui/references/guidelines/forms.md +++ b/plugins/nuxt-ui/agent/skills/nuxt-ui/references/guidelines/forms.md @@ -181,14 +181,14 @@ function onSubmit(event: FormSubmitEvent) { const form = useTemplateRef('form') async function validateAndSubmit() { - const result = await form.value?.validate() + const result = await form.value?.validate({ silent: true }) if (result) { // valid — submit } } async function validateEmail() { - await form.value?.validate({ name: 'email' }) + await form.value?.validate({ name: 'email', silent: true }) } function setServerError() { @@ -198,7 +198,7 @@ function setServerError() { } function resetErrors() { - form.value?.clearErrors() + form.value?.clear() } @@ -209,6 +209,8 @@ function resetErrors() { ``` +By default, `validate()` throws a `FormValidationException` when validation fails. Pass `{ silent: true }` when you want it to return `false` instead. Use `clear()` to remove validation errors. + ## Form in a modal Use `#footer="{ close }"` scoped slot for cancel/submit actions. Wrap the modal body in `UForm` with a `type="submit"` button in the footer so validation runs on submit. diff --git a/plugins/nuxt-ui/agent/skills/nuxt-ui/references/layouts/chat.md b/plugins/nuxt-ui/agent/skills/nuxt-ui/references/layouts/chat.md index 5ba3b6c8..070f4abc 100644 --- a/plugins/nuxt-ui/agent/skills/nuxt-ui/references/layouts/chat.md +++ b/plugins/nuxt-ui/agent/skills/nuxt-ui/references/layouts/chat.md @@ -200,7 +200,7 @@ function onSubmit() { - `UChatMessage` — individual bubble. Props: `message`, `side` (`'left'`/`'right'`). - `UChatReasoning` — collapsible reasoning block. Auto-opens during streaming, auto-closes when done. Use `isPartStreaming(part)` from `@nuxt/ui/utils/ai`. - `UChatTool` — tool invocation status. Use `isToolStreaming(part)`. Variants: `'inline'` (default), `'card'`. -- `UChatPrompt` — enhanced textarea. Accepts all Textarea props + `error` prop. +- `UChatPrompt` — enhanced textarea for chat. Its typed API exposes a selected subset of `UTextarea` props, forwards additional attributes to the underlying textarea, and adds chat-specific props such as `error` and `submitOnEnter`. - `UChatPromptSubmit` — submit button with automatic status handling (send/stop/reload). - `UChatPalette` — layout wrapper for chat inside overlays. diff --git a/plugins/nuxt-ui/skills-lock.json b/plugins/nuxt-ui/skills-lock.json index b49bde38..46bafb57 100644 --- a/plugins/nuxt-ui/skills-lock.json +++ b/plugins/nuxt-ui/skills-lock.json @@ -5,7 +5,7 @@ "source": "nuxt/ui", "sourceType": "github", "skillPath": "skills/nuxt-ui/SKILL.md", - "computedHash": "f6235ff66b930f4fe3809a55167096c9626ebb806f767fe363f19384e0d84c87" + "computedHash": "9724d09a8196e9c991f7afe29a38837b52b9fff80e9c31c04920b5f520e9cf2b" } } } diff --git a/plugins/orpc/.agents/skills/orpc-migrate/SKILL.md b/plugins/orpc/.agents/skills/orpc-migrate/SKILL.md index 279adfad..c47f78b0 100644 --- a/plugins/orpc/.agents/skills/orpc-migrate/SKILL.md +++ b/plugins/orpc/.agents/skills/orpc-migrate/SKILL.md @@ -100,7 +100,8 @@ Most v1 names still compile through deprecated aliases (strike-through hints, no - `RPCLink`: the single `url` split into `origin` plus a path-only `url`. - Errors: `status` was removed from `ORPCError` and `.errors` definitions; map codes to HTTP status with `errorStatusMap` on the handler. - `safe()`: the third tuple element is now the typed error itself (or `null`) and a fourth `isSuccess` element was added. - - Option renames, scoped: handler `rootInterceptors` to `routingInterceptors` (handler `clientInterceptors` still exists, unchanged); link `clientInterceptors` to `transportInterceptors`; on both, `adapterInterceptors` is renamed after the adapter, e.g. `fetchInterceptors` on the fetch adapter. Flat `eventIterator*` options moved under the adapter's request/response mapping: `toFetchResponse.eventStream` on the fetch handler, `sendStandardResponse.eventStream` on Node, `toFetchRequest.eventStream` on the link. + - Option renames, scoped: handler `rootInterceptors` to `routingInterceptors` (handler `clientInterceptors` still exists, unchanged); link `clientInterceptors` to `transportInterceptors`. Flat `eventIterator*` options moved under the adapter's request/response mapping: `toFetchResponse.eventStream` on the fetch handler, `sendStandardResponse.eventStream` on Node, `toFetchRequest.eventStream` on the link. + - `adapterInterceptors` was removed from handlers and links, because regular interceptors can now customize body parsing behavior. 3. **Audit silent behavior changes** (compile fine, behave differently): - **Wire format changed:** a v1 link cannot talk to a v2 server, in either direction. Deploy the upgraded server and clients together. - **Automatic middleware deduplication removed:** middleware applied at both router and procedure level now runs twice, with no warning. Guard shared middleware with the context-flag pattern from the dedupe-middleware recipe. diff --git a/plugins/orpc/.claude/skills/orpc b/plugins/orpc/.claude/skills/orpc new file mode 120000 index 00000000..a5e88378 --- /dev/null +++ b/plugins/orpc/.claude/skills/orpc @@ -0,0 +1 @@ +../../.agents/skills/orpc \ No newline at end of file diff --git a/plugins/orpc/.claude/skills/orpc-contract b/plugins/orpc/.claude/skills/orpc-contract new file mode 120000 index 00000000..06956f2e --- /dev/null +++ b/plugins/orpc/.claude/skills/orpc-contract @@ -0,0 +1 @@ +../../.agents/skills/orpc-contract \ No newline at end of file diff --git a/plugins/orpc/.claude/skills/orpc-migrate b/plugins/orpc/.claude/skills/orpc-migrate new file mode 120000 index 00000000..c2479547 --- /dev/null +++ b/plugins/orpc/.claude/skills/orpc-migrate @@ -0,0 +1 @@ +../../.agents/skills/orpc-migrate \ No newline at end of file diff --git a/plugins/orpc/.claude/skills/orpc-openapi b/plugins/orpc/.claude/skills/orpc-openapi new file mode 120000 index 00000000..f51f9635 --- /dev/null +++ b/plugins/orpc/.claude/skills/orpc-openapi @@ -0,0 +1 @@ +../../.agents/skills/orpc-openapi \ No newline at end of file diff --git a/plugins/orpc/agent/skills/orpc-contract/SKILL.md b/plugins/orpc/agent/skills/orpc-contract/SKILL.md new file mode 100644 index 00000000..a2125fad --- /dev/null +++ b/plugins/orpc/agent/skills/orpc-contract/SKILL.md @@ -0,0 +1,167 @@ +--- +name: orpc-contract +description: Design oRPC v2 APIs contract-first, defining the API shape with oc + from `@orpc/contract`, implementing it with implement from `@orpc/server`, and + consuming the contract from typesafe clients. Use when a project depends on + `@orpc/contract`, when defining a contract with oc, implementing a contract + with implement, sharing an API contract between server and client packages, + generating a contract from an existing OpenAPI spec, or publishing a typed API + client to npm. Biases toward retrieval from the oRPC docs over pre-trained + knowledge. For core builder, serving, and client work without a contract, use + the orpc skill; for REST/OpenAPI exposure, spec generation, and OpenAPILink + details, use the orpc-openapi skill. +license: MIT +--- +# oRPC Contract-First + +Contract-first oRPC splits an API into two artifacts: a contract (schemas, errors, metadata, no business logic) defined with `oc` from `@orpc/contract`, and an implementation built from it with `implement` from `@orpc/server`. Server and client both depend on the contract, never on each other, so the API shape can live in its own package, be reviewed on its own, and ship to consumers as a typed SDK. Prefer it when server and client are separate packages or teams, when the shape starts from an existing OpenAPI spec, or when publishing a client to npm. Stay with the `os`-first flow when one codebase holds both sides and the client can import the router type directly; converting later is cheap because a plain router already works as a router contract (resolve lazy routers with `unlazyRouter` first). + +This skill targets oRPC v2. The `orpc` skill carries the v2 install and version check plus core builder, middleware, serving, and client concepts. Pretrained oRPC knowledge describes v1 and is often wrong for v2: when unsure of any API below, fetch its docs page first (see [Full documentation](#full-documentation)). + +## Define the contract with oc + +Every chain is optional and each call returns a new instance, so share base contracts freely. A contract has no `.handler`. Zod, Valibot, ArkType, and any other Standard Schema library work. + +```ts +import { oc } from '@orpc/contract' +import * as z from 'zod' + +export const contract = { + planet: { + list: oc + .output(z.array(z.object({ id: z.number(), name: z.string() }))), + find: oc + .errors({ NOT_FOUND: {} }) + .input(z.object({ id: z.number() })) + .output(z.object({ id: z.number(), name: z.string() })), + }, +} +``` + +- Always define `.output`: without it clients infer the output as `unknown`. +- A router contract is a plain object mapping keys to procedure contracts or nested objects. Avoid the keys `then`, `bind`, `valueOf`, `toString`, `toJSON`. +- Attach shared metadata to a whole subtree with `oc.meta(someMeta).router({...})`. +- `.errors({ NOT_FOUND: {} })` declares typesafe errors; implementations throw them via `errors.NOT_FOUND()` and clients infer their shapes. +- Repeated `.input`/`.output` calls stack schemas instead of replacing them: object input schemas compose into one flat value, output schemas pipe. Use this to extend a base contract without repeating fields. +- Schema-library-free contracts use the `type` utility from `@orpc/contract`: `oc.input(type<{ value: number }>())`, optionally with a mapping function as `type(fn)`. +- REST routes attach via `.meta(openapi({ method: 'GET', path: '/planets/{id}' }))` from `@orpc/openapi`, exactly as on `os`; routing rules, `prefix`, and spec generation belong to the `orpc-openapi` skill. + +Infer types with `InferRouterContractInputs`, `InferRouterContractOutputs`, and `InferRouterContractErrors` from `@orpc/contract`. + +## Implement with implement + +`implement` turns the contract into an implementer that mirrors its shape and type-checks every handler; `.router` also enforces the contract at runtime. + +```ts +import { implement } from '@orpc/server' + +const implementer = implement(contract).$context<{ db: DB }>() + +const listPlanets = implementer.planet.list.handler(async ({ context }) => context.db.list()) + +const findPlanet = implementer.planet.find.handler(async ({ input, context, errors }) => { + const planet = await context.db.find(input.id) + if (!planet) + throw errors.NOT_FOUND() + return planet +}) + +export const router = implementer.router({ + planet: { list: listPlanets, find: findPlanet }, +}) +``` + +- `.$context` declares the initial context the procedures require, as on `os`. +- Apply middleware per procedure with `.use(mw)` before `.handler`. That runs after input validation (the contract already registered `.input`); to wrap validation, apply it at router level: `implementer.use(mw)` for every procedure, or `implementer.planet.use(mw).list` for a subtree. Router-level plus procedure-level `.use` can run the same middleware twice; use the dedupe pattern from the `orpc` skill. +- `implementer.middleware(fn)` creates middleware that infers the contract's typesafe errors. When not every procedure defines a code, guard with the `in` operator: `if ('TOO_MANY_REQUESTS' in errors) throw errors.TOO_MANY_REQUESTS()`. Any type-compatible middleware also works. +- The result is a normal router: serve it with `RPCHandler` (`orpc` skill) or `OpenAPIHandler` (`orpc-openapi` skill), call it in-process with `call` or `createRouterClient` from `@orpc/server`. + +## Consume the contract from clients + +`RPCLink` needs only the contract type; `OpenAPILink` takes the contract as a runtime value to read each procedure's route. Get the client types exactly right: + +```ts +import type { RouterContractClient } from '@orpc/contract' +import type { JsonifiedClient } from '@orpc/openapi' +import { createORPCClient } from '@orpc/client' +import { RPCLink } from '@orpc/client/fetch' +import { OpenAPILink } from '@orpc/openapi/fetch' + +// RPC protocol (server side is RPCHandler) +const rpcLink = new RPCLink({ origin: 'https://api.example.com', url: '/rpc' }) +const client: RouterContractClient = createORPCClient(rpcLink) + +// OpenAPI protocol (OpenAPIHandler or any spec-compliant server) +const openapiLink = new OpenAPILink(contract, { origin: 'https://api.example.com', url: '/api' }) +const apiClient: JsonifiedClient> = createORPCClient(openapiLink) +``` + +- Router-first equivalents use `RouterClient` from `@orpc/server` in the same positions. +- `JsonifiedClient` is required over `OpenAPILink` because OpenAPI serialization is one-way (a `Date` returns as a string); dropping it via Smart Coercion, plus `OpenAPILink` options and CORS caveats, are in the `orpc-openapi` skill. +- Per-call client context is the second type parameter, `RouterContractClient`, then `client.planet.find(input, { context: { token } })`; link options like `headers` accept functions of that context. +- Export `RouterContractClient` as a type from the server package so clients never import the contract module itself (still needed as a runtime value for `OpenAPILink`; ship the minified JSON below). +- In very large codebases, skip the root client: pin each procedure with `.meta(meta.path([...]))` and build per-procedure clients with `createContractClientFactory` from `@orpc/contract` (`createContractJsonifiedClientFactory` from `@orpc/openapi` when the link needs `JsonifiedClient`); fetch `contract/client-factory` before adopting it. + +## Ship the contract + +When the contract is derived from a router, importing it on the client is heavy and may expose internals. Minify and export JSON instead: + +```ts +import fs from 'node:fs' +import { minifyRouterContract } from '@orpc/contract' +import { unlazyRouter } from '@orpc/server' + +const minified = minifyRouterContract(await unlazyRouter(router)) +fs.writeFileSync('./contract.json', JSON.stringify(minified)) +``` + +`minifyRouterContract` keeps only client-needed metadata. On the client, import the JSON and cast, since schemas do not survive serialization: `new OpenAPILink(contract as typeof router, ...)`. + +To publish a typed SDK to npm, export a factory that pairs the contract with a link: + +```ts +import type { RouterContractClient } from '@orpc/contract' +import { createORPCClient } from '@orpc/client' +import { RPCLink } from '@orpc/client/fetch' + +export function createMyApi(apiKey: string): RouterContractClient { + const link = new RPCLink({ + origin: 'https://example.com', + url: '/rpc', + headers: { 'x-api-key': apiKey }, + }) + return createORPCClient(link) +} +``` + +Bundle with `tsdown --dts src/index.ts`, point `exports` at `dist` types plus import entries, list `@orpc/client` and `@orpc/contract` as dependencies, and publish. Consumers get a fully typed client that works with every oRPC client integration (TanStack Query included). Fetch `recipes/publish-client-to-npm` for the complete `package.json`. + +## Generate the contract from an existing OpenAPI spec + +Use Hey API's `orpc` plugin instead of hand-writing the contract. Install `@hey-api/openapi-ts@next` as a dev dependency (oRPC v2 output requires the `next` tag until the next stable Hey API release) and create `openapi-ts.config.ts`: + +```ts +import { defineConfig } from '@hey-api/openapi-ts' + +export default defineConfig({ + input: 'https://example.com/openapi.json', // local file or URL + output: 'src/contract', + plugins: [{ name: 'orpc', compatibilityVersion: '2', validator: 'zod' }], +}) +``` + +Then run `npx @hey-api/openapi-ts`. It writes `orpc.gen.ts` (one procedure contract per operation, routed via `.meta(openapi({...}))` with `inputStructure: 'detailed'`, plus a combined `contract` router) and `zod.gen.ts`. The generated files import `@orpc/contract`, `@orpc/openapi`, and `zod`, so install those too. From there, implement the contract on your own server, or point `OpenAPILink` at the existing spec-compliant server. + +## Full documentation + +If this skill and a fetched docs page disagree, trust the page: this skill is a summary and v2 is still moving. The docs are served at https://orpc.dev (the v1 docs stay at https://v1.orpc.dev): + +- https://orpc.dev/llms.txt : index of every page with descriptions +- https://orpc.dev/llms-full.txt : the entire docs in one file (large; prefer single pages) +- Append `.md` to any docs URL for that page's exact source markdown (for example https://orpc.dev/docs/contract/procedure.md) + +Pages to fetch when you need details beyond this skill: + +- Contract: `contract/procedure`, `contract/router`, `contract/implementation`, `contract/generate-from-openapi` +- Clients: `client/client-side`, `client/server-side`, `client/error-handling`, `openapi/link` +- Workflows: `recipes/publish-client-to-npm`, `contract/client-factory`, `recipes/monorepo-setup` diff --git a/plugins/orpc/agent/skills/orpc-migrate/SKILL.md b/plugins/orpc/agent/skills/orpc-migrate/SKILL.md new file mode 100644 index 00000000..e9551713 --- /dev/null +++ b/plugins/orpc/agent/skills/orpc-migrate/SKILL.md @@ -0,0 +1,131 @@ +--- +name: orpc-migrate +description: "Migrate existing codebases to current oRPC, covering tRPC to oRPC + (incremental wrapping via the @orpc/trpc integration or a full rewrite with + the concept mapping) and oRPC v1 to v2 (package renames, breaking changes, and + a safe order of operations). Use when asked to migrate from tRPC to oRPC, + convert or wrap a tRPC router, upgrade oRPC v1 to v2, fix oRPC v2 breaking + changes, or swap `@trpc/*` packages for `@orpc/*` equivalents. Biases toward + retrieval from the oRPC docs over pre-trained knowledge. Not for greenfield + oRPC work or new features in an already-migrated codebase: use the orpc skill + for those." +license: MIT +--- +# Migrating to oRPC + +Playbook for two migrations: tRPC to oRPC, and oRPC v1 to v2. Work in small mechanical steps and run the project's typecheck and test suite after each one, so any failure points at the last step. Pretrained knowledge of oRPC describes v1 and is often wrong for v2: derive every import path, builder method, and option name from the docs pages listed at the end, never from memory. For core v2 concepts while rewriting (the `os` builder, routers, middleware, clients), load the `orpc` skill. v2 currently ships under the `beta` npm dist-tag and plain installs get v1; drop the `@beta` suffix once `npm view @orpc/server dist-tags` shows `latest` at 2.x. + +## tRPC to oRPC + +Two paths. Pick incremental when the app must keep shipping or the tRPC router is large; pick the full rewrite when the router is small enough to convert in one pass. + +### Incremental: wrap the existing tRPC router + +Install `@orpc/trpc@beta` and convert. The result is a regular oRPC router: expose it through an RPC or OpenAPI handler, or call it with a server-side client, while the tRPC code keeps working untouched. + +```ts +import { toORPCRouter } from '@orpc/trpc' + +const orpcRouter = toORPCRouter(trpcRouter) +``` + +- tRPC error formatting is not supported: tRPC errors arrive wrapped in `ORPCError` with the `TRPCError` as `cause` (and a `ZodError` below that for validation failures). Reshape them in a handler interceptor if consumers need structured errors. +- `toTRPCMeta` bridges oRPC `openapi()` metadata into tRPC `.meta()` so converted procedures get OpenAPI routing. Chained tRPC `.meta()` calls merge shallowly, so keep all oRPC metadata inside a single `toTRPCMeta` call. + +Then rewrite leaf routers to native oRPC one at a time, mounting each next to the converted router in one plain object. + +### Full rewrite: concept map + +| Concept | tRPC | oRPC | +| ----------------- | ---------------------------------------------- | ------------------------------ | +| Router | `t.router({...})` | plain object | +| Procedure builder | `t.procedure` | `os` | +| Context | `initTRPC.context()` | `os.$context()` | +| Create middleware | `t.middleware(fn)` | `os.middleware(fn)` | +| Use middleware | `.use(mw)` | `.use(mw)` | +| Validation | `.input(schema)` / `.output(schema)` | same names | +| Implementation | `.query()` / `.mutation()` / `.subscription()` | `.handler()` for all three | +| Errors | `new TRPCError({ code, ... })` | `new ORPCError(code, { ... })` | +| Serializer | `superjson` transformer | built in, remove `superjson` | + +Steps, in order, verifying after each: + +1. **Packages.** Remove `@trpc/server`, `@trpc/client`, `@trpc/tanstack-react-query`; install `@orpc/server@beta`, `@orpc/client@beta`, `@orpc/tanstack-query@beta`. +2. **Base file.** Port the context factory unchanged, then rebuild the shared procedures. In handlers and middleware, `ctx` becomes `context`: + + ```ts + import { ORPCError, os } from '@orpc/server' + + const o = os.$context>>() + + export const publicProcedure = o.use(timingMiddleware) + export const protectedProcedure = publicProcedure.use(({ context, next }) => { + if (!context.session?.user) + throw new ORPCError('UNAUTHORIZED') + return next({ context: { session: context.session } }) + }) + ``` + +3. **Procedures.** Replace `.query`/`.mutation`/`.subscription` with `.handler`; `.input` and `.output` carry over as is. +4. **App router.** Delete every `createTRPCRouter()` wrapper; nested plain objects are the router. +5. **Server.** Replace the tRPC adapter with an oRPC handler for the runtime (fetch shown; other adapters exist for Node, Fastify, AWS Lambda, WebSocket): + + ```ts + import { RPCHandler } from '@orpc/server/fetch' + + const handler = new RPCHandler(appRouter) + + const { response } = await handler.handle(request, { + prefix: '/api/orpc', + context: await createContext({ headers: request.headers }), + }) + ``` + +6. **Client.** `RPCLink` plus `createORPCClient`, typed by `RouterClient`. Call sites drop the `.query()`/`.mutate()` suffixes: + + ```ts + import type { RouterClient } from '@orpc/server' + import { createORPCClient } from '@orpc/client' + import { RPCLink } from '@orpc/client/fetch' + + const link = new RPCLink({ origin: 'http://localhost:3000', url: '/api/orpc' }) + export const client: RouterClient = createORPCClient(link) + + const { planets } = await client.planet.list({ cursor: 0 }) + ``` + +7. **TanStack Query.** `createTanstackQueryUtils(client)` replaces the provider and `useTRPC` hook entirely; use the utils object directly. Input moves inside an `input` key: `orpc.planet.list.queryOptions({ input: { cursor: 0 } })`, `orpc.planet.create.mutationOptions()`. For infinite queries, `infiniteOptions` takes `input` as a function of the page param. + +## oRPC v1 to v2 + +Most v1 names still compile through deprecated aliases (strike-through hints, not errors), so migrate in passes. Order of operations: + +1. **Update packages.** Install every `@orpc/*` package from the `beta` dist-tag (`npm install @orpc/server@beta @orpc/client@beta`, and so on). Swap renamed ones first: `@orpc/react-query`/`@orpc/vue-query`/`@orpc/solid-query`/`@orpc/svelte-query` all became `@orpc/tanstack-query`; `@orpc/openapi-client` merged into `@orpc/openapi`; `@orpc/react` became `@orpc/next`; `@orpc/otel` became `@orpc/opentelemetry`; the `experimental-` packages were promoted (`@orpc/publisher`, `@orpc/ratelimit`, `@orpc/pino`, `@orpc/swr`); `@orpc/vue-colada` became `@orpc/pinia-colada`. Typecheck: the remaining errors are the hard breaks. +2. **Fix the hard breaks** (no aliases): + - Routing: `.route`, `.prefix`, `.tag`, `.$route` are gone from the builder. Use `.meta(openapi({ method, path, prefix, tags }))` from `@orpc/openapi`, or restore `.route` with `import '@orpc/openapi/extensions/route'`. + - `.callable` and `.actionable`: use `call`/`createRouterClient` from `@orpc/server` and `createServerFunctionable` from `@orpc/next`, or the corresponding extension imports. + - `RPCLink`: the single `url` split into `origin` plus a path-only `url`. + - Errors: `status` was removed from `ORPCError` and `.errors` definitions; map codes to HTTP status with `errorStatusMap` on the handler. + - `safe()`: the third tuple element is now the typed error itself (or `null`) and a fourth `isSuccess` element was added. + - Option renames, scoped: handler `rootInterceptors` to `routingInterceptors` (handler `clientInterceptors` still exists, unchanged); link `clientInterceptors` to `transportInterceptors`. Flat `eventIterator*` options moved under the adapter's request/response mapping: `toFetchResponse.eventStream` on the fetch handler, `sendStandardResponse.eventStream` on Node, `toFetchRequest.eventStream` on the link. + - `adapterInterceptors` was removed from handlers and links, because regular interceptors can now customize body parsing behavior. +3. **Audit silent behavior changes** (compile fine, behave differently): + - **Wire format changed:** a v1 link cannot talk to a v2 server, in either direction. Deploy the upgraded server and clients together. + - **Automatic middleware deduplication removed:** middleware applied at both router and procedure level now runs twice, with no warning. Guard shared middleware with the context-flag pattern from the dedupe-middleware recipe. + - **Batch Plugin `exclude` became `filter` with the opposite meaning.** Usually delete `exclude`; if skipping is still needed, negate the predicate. + - **`RPCHandler` rejects GET by default** (`allowMethods` defaults to POST/PUT/PATCH/DELETE). Simplest fix: stop sending GET from the link; only allow GET deliberately, with CSRF protection. + - **Handler `filter` takes positional arguments now;** the v1 destructured form still type-checks but reads wrong values. + - **`.input`/`.output` now stack:** a repeated call adds a schema instead of replacing the previous one. +4. **Sweep deprecated aliases** last: `eventIterator` to `asyncIteratorObject`, handler plugins gained a `HandlerPlugin` suffix and link plugins a `LinkPlugin` suffix, `ContractRouter*` types became `RouterContract*`. The from-v1 guide ends with the full alias cheat sheet. + +Verification: typecheck and unit tests after steps 1, 2, and 4; step 3 needs integration or e2e tests, since those changes never surface at compile time. Before finishing, grep for old package names and remaining deprecation strike-throughs. + +## Docs retrieval + +Fetch pages instead of recalling them, and if this skill and a fetched page disagree, trust the page. The v2 docs live at https://orpc.dev and the v1 docs at https://v1.orpc.dev; slugs look alike across both hosts, so check which host a page came from before copying anything from it. The index of every v2 docs page is at https://orpc.dev/llms.txt, https://orpc.dev/llms-full.txt bundles the entire docs in one large file, and appending `.md` to any page URL returns its exact source markdown. + +Authoritative pages to consult during the migration (this skill deliberately omits their full mapping tables): + +- https://orpc.dev/docs/migrations/from-trpc : side-by-side tRPC/oRPC code for every step, including server setup per framework +- https://orpc.dev/docs/migrations/from-v1 : every v2 breaking change with v1/v2 comparisons, package rename table, and the deprecated alias cheat sheet +- https://orpc.dev/docs/integrations/trpc : `toORPCRouter` and `toTRPCMeta` reference for the incremental path diff --git a/plugins/orpc/agent/skills/orpc-openapi/SKILL.md b/plugins/orpc/agent/skills/orpc-openapi/SKILL.md new file mode 100644 index 00000000..254b90bc --- /dev/null +++ b/plugins/orpc/agent/skills/orpc-openapi/SKILL.md @@ -0,0 +1,161 @@ +--- +name: orpc-openapi +description: Expose an oRPC router as a spec-compliant OpenAPI HTTP API. Use + when a project depends on @orpc/openapi, or for defining REST-style routes on + oRPC procedures (openapi() metadata or .route with method, path, + successStatus), serving them with OpenAPIHandler alongside RPCHandler, + coercing query and path strings with Smart Coercion, calling an OpenAPI-shaped + API with OpenAPILink, generating an OpenAPI 3.2 (or 3.1, 3.0) document with + OpenAPIGenerator, or serving Scalar or Swagger docs with the OpenAPI Reference + plugin. Biases toward retrieval from the oRPC docs over pre-trained knowledge. + For contract-first work (defining contracts with oc, implementing them with + implement, or generating a contract from an existing OpenAPI spec), use the + orpc-contract skill; for plain RPC serving, core builder, middleware, or + client work with no REST exposure, use the orpc skill instead. +license: MIT +--- +# oRPC over OpenAPI + +oRPC procedures speak two protocols from one router: the RPC protocol (`RPCHandler`/`RPCLink`) and plain OpenAPI HTTP (`OpenAPIHandler`/`OpenAPILink`). This skill covers the OpenAPI side. For core builder, middleware, context, and client concepts, load the `orpc` skill (it also carries the v2 install and version check); for contract-first workflows with `@orpc/contract`, load the `orpc-contract` skill. + +This skill targets oRPC v2. Pretrained oRPC knowledge describes v1 and is often wrong for v2: when unsure of any API below, fetch its exact docs page first (see [Full documentation](#full-documentation)). + +## Routing + +A procedure defaults to `POST` with a path derived from the router structure (`planet.create` becomes `POST /planet/create`). Override with `openapi` metadata, on server (`os`) and contract (`oc`) builders alike: + +```ts +import { openapi } from '@orpc/openapi' +import { os } from '@orpc/server' +import { z } from 'zod' + +const getPlanet = os + .meta(openapi({ method: 'GET', path: '/planets/{id}', successStatus: 200 })) + .input(z.object({ id: z.string() })) + .handler(async ({ input }) => ({ id: input.id, name: 'Earth' })) +``` + +- Path params: put `{id}` in `path` and the same key as a required field in the input schema. Use `{+path}` for catch-all segments that may contain `/`. +- `prefix` prepends a path to a procedure or a whole router: `os.meta(openapi({ prefix: '/api/v2' })).router({...})`. Always set a `prefix` on lazy routers so lazy loading only triggers for relevant requests. +- Merging across repeated `.meta(openapi(...))` calls: `prefix` and `tags` concatenate, `method`/`path`/`successStatus` last-wins, and setting a field to `undefined` resets it to the default. +- `successStatus` defaults to `200` and must be below 400. + +For direct routing without `.meta(openapi(...))`, enable the `.route` extension with a side-effect import in a module that always runs at startup (base builder file or server entry): + +```ts +import '@orpc/openapi/extensions/route' + +const ping = os.route({ method: 'GET', path: '/ping' }).handler(async () => 'pong') +``` + +## Input and output mapping + +Compact mode (default): path params merge with query params or the request body depending on the HTTP method, so `GET /planets/earth?q=life` yields input `{ id: 'earth', q: 'life' }`. The handler's return value becomes the response body with status `successStatus`. + +Set `inputStructure: 'detailed'` in the metadata to receive `{ params, query, headers, body }` instead (define only the fields you need in the input schema). Set `outputStructure: 'detailed'` to return `{ status?, headers?, body? }` and vary the status per response. + +Query strings and form data are decoded with bracket notation (fetch `openapi/bracket-notation` before designing schemas for nested query input; its limits are not guessable): + +- Repeated keys become arrays: `?color=red&color=blue` gives `['red', 'blue']`; `color[]=red` pushes too. +- `[number]` targets an array index; `[key]` targets an object property: `?filter[status]=active` gives `{ filter: { status: 'active' } }`. +- It cannot represent empty objects or arrays, root-level arrays, or objects whose keys are all numbers, and query/form values always arrive as strings (or files, in form data). + +Override decoding per parameter with `paramsStyles` (`'primitive'`, `'comma-delimited-array'`, `'comma-delimited-object'`) and `queryStyles` (those plus `'array'`, `'json'`, and space/pipe-delimited variants). Use `requestBodyHint`/`responseBodyHint` (`'json'`, `'form-data'`, `'event-stream'`, `'octet-stream'`, `'file'`, ...) when headers alone cannot tell the parser how to handle the body, for example a raw `ReadableStream` upload. + +## Serving: OpenAPIHandler + +Import from the adapter subpath (`@orpc/openapi/fetch`, `@orpc/openapi/node`, ...): + +```ts +import { SmartCoercionHandlerPlugin } from '@orpc/json-schema' +import { OpenAPIHandler } from '@orpc/openapi/fetch' +import { ZodToJsonSchemaConverter } from '@orpc/zod' + +const handler = new OpenAPIHandler(router, { + plugins: [ + new SmartCoercionHandlerPlugin({ converters: [new ZodToJsonSchemaConverter()] }), + ], +}) + +export async function fetch(request: Request): Promise { + const { matched, response } = await handler.handle(request, { prefix: '/api', context: {} }) + return matched ? response : new Response('Not Found', { status: 404 }) +} +``` + +`OpenAPIHandler` coexists with `RPCHandler`: both accept the same router, so mount them on different prefixes (for example `/api` and `/rpc`) and try each in turn, returning the first `matched` response. + +Smart Coercion: query, path, and form values arrive as strings, so add `SmartCoercionHandlerPlugin` whenever input schemas expect non-string types from those sources. It coerces schema-driven, lossless conversions only (`'123'` to `123`, `'true'`/`'on'` to `true`, ISO strings to `Date`, arrays to `Set`/`Map` via `x-native-type`) and leaves ambiguous values untouched. Skip it when you already coerce in the schema or performance is critical; it adds runtime overhead. + +Other handler options: `interceptors`/`routingInterceptors`/`clientInterceptors` for logging and error mapping, `filter` to exclude procedures from matching, and `errorStatusMap` plus `customErrorResponseBodyEncoder` to customize error responses (by default `ORPCError` codes map to statuses via `COMMON_ERROR_STATUS_MAP`, for example `NOT_FOUND` to 404). + +## Calling: OpenAPILink + +`OpenAPILink` calls an OpenAPI-shaped oRPC API (or any spec-compliant server) through a typesafe client. It needs the contract or router type to know each procedure's route: + +```ts +import type { RouterContractClient } from '@orpc/contract' +import type { JsonifiedClient } from '@orpc/openapi' +import { createORPCClient } from '@orpc/client' +import { OpenAPILink } from '@orpc/openapi/fetch' + +const link = new OpenAPILink(contract, { + origin: 'https://api.example.com', + url: '/api', + headers: ({ context }) => ({ + authorization: context?.token ? `Bearer ${context.token}` : undefined, + }), +}) + +const client: JsonifiedClient> = createORPCClient(link) +``` + +With a router instead of a contract, type the client as `JsonifiedClient>` (`RouterClient` from `@orpc/server`). `JsonifiedClient` exists because OpenAPI serialization is one-way: a `Date` returns as a string. Add `SmartCoercionLinkPlugin` from `@orpc/json-schema` (same converters, first argument is the contract) to restore native types on responses, then drop the `JsonifiedClient` wrapper from the client type. + +To ship a contract to clients without bundling server code, minify it to JSON and import it with a cast; the flow is in the `orpc-contract` skill under "Ship the contract". + +## Spec document and interactive docs + +`OpenAPIGenerator` turns a router or contract into an OpenAPI 3.2 document (pass any `3.1.x` or `3.0.x` `version` for tools that stop at an older version; `QUERY` procedures need 3.2). `OpenAPIReferenceHandlerPlugin` serves the spec at `/spec.json` and a Scalar UI at `/` under the handler prefix (change with `specPath`/`docsPath`, or set `provider: 'swagger'` for Swagger UI): + +```ts +import { OpenAPIGenerator } from '@orpc/openapi' +import { OpenAPIReferenceHandlerPlugin } from '@orpc/openapi/plugins' +import { ZodToJsonSchemaConverter } from '@orpc/zod' + +const generator = new OpenAPIGenerator({ converters: [new ZodToJsonSchemaConverter()] }) + +const handler = new OpenAPIHandler(router, { + plugins: [ + new OpenAPIReferenceHandlerPlugin({ + spec: () => generator.generate(router, { + base: { + info: { title: 'Planet API', version: '1.0.0' }, + servers: [{ url: '/api' }], // absolute URL in production + }, + }), + }), + ], +}) +``` + +Enrich the document through `openapi` metadata: `operationId`, `summary`, `description`, `tags`, `successDescription`, and a `spec` callback that receives the generated operation object and returns an extended one (security requirements, extra responses). Write `spec` and `base` as OpenAPI 3.2 objects even when generating 3.1 or 3.0; the generator downgrades the whole document. Converters also exist for Valibot (`@orpc/valibot`) and ArkType (`@orpc/arktype`); schemas without a matching converter fall back to Standard JSON Schema conversion. + +Verify the wiring before declaring success: request `/spec.json` under the handler prefix and one routed endpoint, and confirm the method, path, and status you configured. + +## Contract-first + +Contract-first workflows belong to the `orpc-contract` skill: defining the shape with `oc` from `@orpc/contract`, implementing it with `implement` from `@orpc/server`, consuming the contract from clients, shipping it as minified JSON, and generating it from an existing OpenAPI spec with Hey API. On the OpenAPI side a contract behaves exactly like a router: attach routes with `.meta(openapi({...}))` on `oc` as shown in [Routing](#routing), serve the implemented router with `OpenAPIHandler` as usual, generate the spec document from the contract directly, and give `OpenAPILink` the contract as its runtime value. + +## Full documentation + +If this skill and a fetched docs page disagree, trust the page: this skill is a summary and v2 is still moving. The docs are served at https://orpc.dev (the v1 docs stay at https://v1.orpc.dev): + +- https://orpc.dev/llms.txt : index of every page with descriptions +- https://orpc.dev/llms-full.txt : the entire docs in one file (large; prefer single pages) +- Append `.md` to any docs URL for that page's exact source markdown (for example https://orpc.dev/docs/openapi/routing.md) + +Pages to fetch when you need details beyond this skill: + +- OpenAPI: `openapi/routing`, `openapi/input-and-output-mapping`, `openapi/bracket-notation`, `openapi/serializer`, `openapi/handler`, `openapi/link`, `openapi/specification`, `openapi/scalar` +- Plugins: `plugins/smart-coercion`, `plugins/openapi-reference` diff --git a/plugins/orpc/agent/skills/orpc/SKILL.md b/plugins/orpc/agent/skills/orpc/SKILL.md new file mode 100644 index 00000000..8efcea93 --- /dev/null +++ b/plugins/orpc/agent/skills/orpc/SKILL.md @@ -0,0 +1,248 @@ +--- +name: orpc +description: "Build, serve, and call end-to-end typesafe APIs with oRPC v2. Use + for any task in a project that depends on `@orpc/*` packages, even a + one-procedure change: defining procedures with the os builder + (.input/.output/.handler, any Standard Schema validator), assembling routers, + middleware and context, typesafe errors with ORPCError, serving via RPCHandler + on any runtime adapter, calling from server-side clients (call, + createRouterClient) or client-side clients (createORPCClient with RPCLink), + integrating TanStack Query, or streaming over SSE. Pretrained oRPC knowledge + describes v1 and is wrong for v2, so load this skill even when the change + looks trivial. Biases toward retrieval from the oRPC docs over pre-trained + knowledge. For REST/OpenAPI exposure, prefer the orpc-openapi skill; for + contract-first design, the orpc-contract skill; for tRPC or oRPC v1 + migrations, the orpc-migrate skill." +license: MIT +--- +# oRPC + +oRPC is a typesafe API framework: write plain TypeScript functions on the server, call them from clients like local functions. Input is validated at runtime, types flow end to end, and there is no code generation step. The same router can also be served as a REST API with an OpenAPI spec. + +This skill targets oRPC v2. Check what is installed before writing code: `npm ls @orpc/server` (or any `@orpc/*` package). A 1.x version means v1, where this skill's guidance does not apply; use the `orpc-migrate` skill to upgrade. v2 currently ships under the `beta` dist-tag (`npm install @orpc/server@beta @orpc/client@beta`; a plain install silently gets v1). If `npm view @orpc/server dist-tags` shows `latest` at 2.x, the beta has ended: install normally. + +Pretrained oRPC knowledge describes v1 and is often wrong for v2 (routing moved to `.meta(openapi(...))`, `RPCLink` split `url` into `origin` plus a path, automatic middleware dedupe was removed). Prefer retrieval: the index of every docs page is at https://orpc.dev/llms.txt; see [Full documentation](#full-documentation) for the mechanics. + +Package map: + +- `@orpc/server`: the `os` builder, routers, middleware, `RPCHandler`, server-side clients (`call`, `createRouterClient`), `implement` for mocks +- `@orpc/client`: `createORPCClient`, `RPCLink`, `safe`, `createSafeClient`, `isDefinedError` +- `@orpc/contract`: contract-first API definitions implemented separately from their logic (see the `orpc-contract` skill) +- `@orpc/openapi`: `OpenAPIHandler`, `OpenAPILink`, OpenAPI 3.2 spec generation +- Integration packages such as `@orpc/tanstack-query` and `@orpc/nest` + +## Define procedures + +Build a procedure with the `os` builder: describe input with a schema, implement with `.handler`. Zod, Valibot, ArkType, and any other [Standard Schema](https://standardschema.dev/) library work for `.input`, `.output`, and error `data`. + +```ts +import { os } from '@orpc/server' +import * as z from 'zod' + +export const listPlanets = os + .handler(async () => [{ id: 1, name: 'Earth' }]) // no .input: takes no arguments + +export const findPlanet = os + .input(z.object({ id: z.number() })) + .handler(async ({ input }) => ({ id: input.id, name: 'Earth' })) +``` + +`.handler` is the only required step. The full chain, every other step optional: + +```ts +const example = os + .$context<{ headers: Headers }>() // initial context this procedure requires + .errors({ NOT_FOUND: {} }) // typed errors + .use(requireAuth) // middleware + .input(z.object({ id: z.number() })) + .output(z.object({ id: z.number(), name: z.string() })) // optional; also speeds up type checking + .handler(async ({ input, context, errors }) => ({ id: input.id, name: 'Earth' })) +``` + +Every builder step returns a new instance, so share base builders freely: `const authed = os.use(requireAuth)` then build many procedures from `authed`. + +## Assemble a router + +A router is a plain object mapping keys to procedures (or nested routers). Do not use the keys `then`, `bind`, `valueOf`, `toString`, `toJSON`. + +```ts +export const router = { + planet: { list: listPlanets, find: findPlanet }, + admin: os.use(requireAuth).router({ deletePlanet }), // apply shared middleware to a subtree + planetLazy: os.lazy(() => import('./planet')), // code-split; module's default export is a router +} +``` + +Infer types with `InferRouterInputs` / `InferRouterOutputs` from `@orpc/server`. Applying `.use` at both router and procedure level can run the same middleware twice; see the dedupe pattern below. + +## Middleware and context + +Context comes from two places. Initial context is declared with `.$context` and passed explicitly when serving or calling (environment values: headers, env, db). Injected context is added at runtime by middleware via `next({ context })` (runtime values: the authenticated user). + +```ts +import { ORPCError, os } from '@orpc/server' + +const base = os.$context<{ headers: Headers }>() + +const requireAuth = base.middleware(async ({ context, next }) => { + const user = await parseUser(context.headers) + if (!user) { + throw new ORPCError('UNAUTHORIZED') + } + return next({ context: { user } }) // handler now sees context.user, typed non-null +}) +``` + +`.use` accepts named middleware or inline functions. Middleware registered before `.input` runs before validation, the rest after. Middleware can also declare typed input (`os.middleware(async ({ next }, id: number) => ...)`); adapt mismatched shapes with `.use(mw.adaptInput(input => input.id))`. + +Best practice, dedupe expensive middleware: the same middleware can run twice in one call (router-level plus procedure-level `.use`, or a procedure `call`ing another). Cache the result in context: + +```ts +const authProvider = os + .$context<{ headers: Headers, auth?: { id: string }, authLoaded?: boolean }>() + .middleware(async ({ context, next }) => { + const auth = context.authLoaded ? context.auth : await loadAuth(context.headers) + return next({ context: { auth, authLoaded: true } }) + }) +``` + +## Typesafe errors + +Throw `ORPCError` (a `code` plus optional `message` and `data`). Both `message` and `data` are sent to the client, so never put secrets in them. Throw only `Error` instances, never literals. + +Define errors with `.errors` so clients can infer each error's shape: + +```ts +const find = os + .errors({ + NOT_FOUND: { message: 'Planet not found' }, // default message + RATE_LIMITED: { data: z.object({ retryAfter: z.number() }) }, + }) + .handler(async ({ input, errors }) => { + throw errors.NOT_FOUND() + }) +``` + +`throw new ORPCError('NOT_FOUND')` inside that handler is converted to the matching typed error when code and data match. Convert custom error classes to `ORPCError` in a middleware `try/catch`. + +## Serve with RPCHandler + +`RPCHandler` matches requests to procedures, validates input, runs handlers, and encodes results. Pick the adapter for your runtime. Fetch API (Bun, Deno, Cloudflare Workers): + +```ts +import { onError } from '@orpc/server' +import { RPCHandler } from '@orpc/server/fetch' +import { CORSHandlerPlugin } from '@orpc/server/plugins' + +const handler = new RPCHandler(router, { + plugins: [new CORSHandlerPlugin()], + interceptors: [onError(error => console.error(error))], +}) + +export async function fetch(request: Request): Promise { + const { matched, response } = await handler.handle(request, { + prefix: '/rpc', + context: { headers: request.headers }, // provide the router's initial context here + }) + return matched ? response : new Response('Not found', { status: 404 }) +} +// Bun.serve({ fetch }) / Deno.serve(fetch) / export default { fetch } on Workers +``` + +Node HTTP: + +```ts +import { createServer } from 'node:http' +import { RPCHandler } from '@orpc/server/node' + +const handler = new RPCHandler(router) + +const server = createServer(async (req, res) => { + const { matched } = await handler.handle(req, res, { prefix: '/rpc', context: {} }) + if (matched) + return + res.statusCode = 404 + res.end('Not found') +}) + +server.listen(3000) +``` + +Unmatched requests fall through to your own handling. By default `RPCHandler` accepts only `POST`, `PUT`, `PATCH`, and `DELETE`; enabling `GET` via `allowMethods` is a CSRF risk with cookie auth, see [RPC Handler](https://orpc.dev/docs/rpc/handler). Handler options also include `interceptors`, `routingInterceptors`, `clientInterceptors`, `plugins`, `filter`, and `errorStatusMap`. Adapters also exist for [AWS Lambda](https://orpc.dev/docs/adapters/aws-lambda), [Fastify](https://orpc.dev/docs/adapters/fastify), [WebSocket](https://orpc.dev/docs/adapters/websocket), [Message Port](https://orpc.dev/docs/adapters/message-port), and [Expo](https://orpc.dev/docs/adapters/expo). + +## Call procedures + +Server side (same process, no HTTP; also the fastest way to test procedures): + +```ts +import { call, createRouterClient } from '@orpc/server' + +const planet = await call(findPlanet, { id: 1 }, { context: { headers } }) + +const client = createRouterClient(router, { context: { headers } }) // context can be a function +const planets = await client.planet.list() +``` + +Client side, `RPCLink` turns calls into HTTP requests. Import the router as a type only so no server code reaches the client bundle: + +```ts +import type { RouterClient } from '@orpc/server' +import type { router } from '../server/router' +import { createORPCClient } from '@orpc/client' +import { RPCLink } from '@orpc/client/fetch' + +const link = new RPCLink({ + origin: 'http://127.0.0.1:3000', + url: '/rpc', // must match the server's prefix + headers: () => ({ authorization: `Bearer ${token}` }), // options accept functions +}) + +export const orpc: RouterClient = createORPCClient(link) + +const planet = await orpc.planet.find({ id: 1 }) +``` + +Client error handling: plain `try/catch` works, but `safe` preserves typed error inference: + +```ts +import { createSafeClient, isDefinedError, safe } from '@orpc/client' + +const [error, data] = await safe(orpc.planet.find({ id: 1 })) +if (isDefinedError(error)) { + console.log(error.code, error.data) // typed from the procedure's .errors +} +else if (error) { + // unknown error +} + +const safeClient = createSafeClient(orpc) // every call returns [error, data] +``` + +## Beyond the basics + +- Streaming / SSE: return an async generator from `.handler`, validate events with `asyncIteratorObject`, resume via `lastEventId`: [AsyncIteratorObject](https://orpc.dev/docs/async-iterator-object) +- OpenAPI: serve the same router as REST with routing metadata plus `OpenAPIHandler`, and generate a spec (covered in depth by the `orpc-openapi` skill): [OpenAPI Handler](https://orpc.dev/docs/openapi/handler) +- Contract-first: define contracts with `@orpc/contract`, implement with `implement` (covered in depth by the `orpc-contract` skill): [Contracts](https://orpc.dev/docs/contract/procedure) +- Plugins for handler and link: batch, CORS, dedupe, retry, compression, request limits, smart coercion, static files, timeout, tmp file upload, and more. Fetch a plugin's docs page before configuring it; option names are not guessable: [Plugins](https://orpc.dev/docs/plugins/batch) +- Integrations: [TanStack Query](https://orpc.dev/docs/integrations/tanstack-query) (`createTanstackQueryUtils`), [SWR](https://orpc.dev/docs/integrations/swr), [Pinia Colada](https://orpc.dev/docs/integrations/pinia-colada), [Next.js](https://orpc.dev/docs/integrations/next), [NestJS](https://orpc.dev/docs/integrations/nest), [AI SDK](https://orpc.dev/docs/integrations/ai-sdk), [OpenTelemetry](https://orpc.dev/docs/integrations/opentelemetry) +- Testing: `call` procedures directly; mock with `implement(router.planet.list).handler(() => [])`, and run the project's typecheck before declaring success, since end-to-end types are oRPC's first correctness signal: [Testing and Mocking](https://orpc.dev/docs/recipes/testing-and-mocking) +- Monorepos: TypeScript project references keep client types resolvable: [Monorepo Setup](https://orpc.dev/docs/recipes/monorepo-setup) +- Migrating from tRPC or oRPC v1: use the `orpc-migrate` skill + +## Full documentation + +This skill is an overview; fetch exact docs instead of guessing APIs, and if this skill and a fetched page disagree, trust the page. The docs are served at https://orpc.dev (the v1 docs stay at https://v1.orpc.dev): + +- https://orpc.dev/llms.txt : index of every page with descriptions +- https://orpc.dev/llms-full.txt : the entire docs in one file (large; prefer single pages) +- Append `.md` to any docs URL for that page's exact source markdown (for example https://orpc.dev/docs/procedure.md) + +Doc map, all under `https://orpc.dev/docs/`: + +- Top level: `procedure`, `router`, `middleware`, `context`, `error-handling`, `metadata`, plus `binary-data` (file uploads) and `async-iterator-object` (streaming/SSE) +- `rpc/*`, `openapi/*`: protocol details, handlers, links; `contract/*`: contract-first (the `orpc-contract` skill) +- `client/*`: server- and client-side clients, error handling, `DynamicLink` +- `adapters/*`: per-runtime serving quirks (fetch-api, node-http, aws-lambda, fastify, websocket, message-port, expo) +- `plugins/*`: twenty handler/link plugins; `helpers/*`: cookie, encryption, form-data, lock, publisher, ratelimit, signing, base64url +- `integrations/*`: framework glue; `recipes/*`: guidance (testing, SSR, monorepos, validation) +- `migrations/from-v1`, `migrations/from-trpc`: upgrades (use the `orpc-migrate` skill) diff --git a/plugins/orpc/skills-lock.json b/plugins/orpc/skills-lock.json index 39b4bb2b..80fb6682 100644 --- a/plugins/orpc/skills-lock.json +++ b/plugins/orpc/skills-lock.json @@ -17,7 +17,7 @@ "source": "middleapi/orpc", "sourceType": "github", "skillPath": "skills/orpc-migrate/SKILL.md", - "computedHash": "b8045826a9a78eb51d79b4a0037feca9480b1824aee3095752454fad8bc5d65d" + "computedHash": "8bb9839c8b14c657d1e2b4e96bb8e1a3253c80c2de09b59a369e2c04ddb1032b" }, "orpc-openapi": { "source": "middleapi/orpc", diff --git a/plugins/portless/.agents/skills/portless/SKILL.md b/plugins/portless/.agents/skills/portless/SKILL.md index a8aed422..4ed62f27 100644 --- a/plugins/portless/.agents/skills/portless/SKILL.md +++ b/plugins/portless/.agents/skills/portless/SKILL.md @@ -109,6 +109,8 @@ For turborepo projects, use portless as the `dev` script with the real command i `pnpm dev` runs turbo, which runs `portless` in each package. Portless detects the package manager and runs `pnpm run dev:app` through the proxy. +When `portless` runs from a workspace root, it uses the existing Turbo integration to preserve task ordering when either `turbo.json` or `turbo.jsonc` is readable. Set `"turbo": false` in the root portless configuration to use direct spawning instead. + ### package.json scripts You can still use portless directly in scripts: diff --git a/plugins/portless/agent/skills/portless/SKILL.md b/plugins/portless/agent/skills/portless/SKILL.md index 6d466b5c..6e9d53fe 100644 --- a/plugins/portless/agent/skills/portless/SKILL.md +++ b/plugins/portless/agent/skills/portless/SKILL.md @@ -112,6 +112,8 @@ For turborepo projects, use portless as the `dev` script with the real command i `pnpm dev` runs turbo, which runs `portless` in each package. Portless detects the package manager and runs `pnpm run dev:app` through the proxy. +When `portless` runs from a workspace root, it uses the existing Turbo integration to preserve task ordering when either `turbo.json` or `turbo.jsonc` is readable. Set `"turbo": false` in the root portless configuration to use direct spawning instead. + ### package.json scripts You can still use portless directly in scripts: diff --git a/plugins/portless/skills-lock.json b/plugins/portless/skills-lock.json index f6edef59..25ff23b7 100644 --- a/plugins/portless/skills-lock.json +++ b/plugins/portless/skills-lock.json @@ -5,7 +5,7 @@ "source": "vercel-labs/portless", "sourceType": "github", "skillPath": "skills/portless/SKILL.md", - "computedHash": "3554b1c4b77a327e87dfa1fafe8fec5136c19f5adfb9803a412aab7fd6c16e05" + "computedHash": "c97d5a9840cee601a9f71a1241c014d756d03225a0e9bf54cc849160fa952df8" } } } diff --git a/plugins/react-native/.agents/skills/vercel-react-native-skills/metadata.json b/plugins/react-native/.agents/skills/vercel-react-native-skills/metadata.json new file mode 100644 index 00000000..600eb5bc --- /dev/null +++ b/plugins/react-native/.agents/skills/vercel-react-native-skills/metadata.json @@ -0,0 +1,16 @@ +{ + "version": "1.0.0", + "organization": "Engineering", + "date": "January 2026", + "abstract": "Comprehensive performance optimization guide for React Native applications, designed for AI agents and LLMs. Contains 35+ rules across 13 categories, prioritized by impact from critical (core rendering, list performance) to incremental (fonts, imports). Each rule includes detailed explanations, real-world examples comparing incorrect vs. correct implementations, and specific impact metrics to guide automated refactoring and code generation.", + "references": [ + "https://react.dev", + "https://reactnative.dev", + "https://docs.swmansion.com/react-native-reanimated", + "https://docs.swmansion.com/react-native-gesture-handler", + "https://docs.expo.dev", + "https://legendapp.com/open-source/legend-list", + "https://github.com/nandorojo/galeria", + "https://zeego.dev" + ] +} diff --git a/plugins/react-native/agent/skills/vercel-react-native-skills/metadata.json b/plugins/react-native/agent/skills/vercel-react-native-skills/metadata.json new file mode 100644 index 00000000..600eb5bc --- /dev/null +++ b/plugins/react-native/agent/skills/vercel-react-native-skills/metadata.json @@ -0,0 +1,16 @@ +{ + "version": "1.0.0", + "organization": "Engineering", + "date": "January 2026", + "abstract": "Comprehensive performance optimization guide for React Native applications, designed for AI agents and LLMs. Contains 35+ rules across 13 categories, prioritized by impact from critical (core rendering, list performance) to incremental (fonts, imports). Each rule includes detailed explanations, real-world examples comparing incorrect vs. correct implementations, and specific impact metrics to guide automated refactoring and code generation.", + "references": [ + "https://react.dev", + "https://reactnative.dev", + "https://docs.swmansion.com/react-native-reanimated", + "https://docs.swmansion.com/react-native-gesture-handler", + "https://docs.expo.dev", + "https://legendapp.com/open-source/legend-list", + "https://github.com/nandorojo/galeria", + "https://zeego.dev" + ] +} diff --git a/plugins/react-native/skills-lock.json b/plugins/react-native/skills-lock.json index 8545c572..14674bd4 100644 --- a/plugins/react-native/skills-lock.json +++ b/plugins/react-native/skills-lock.json @@ -5,7 +5,7 @@ "source": "vercel-labs/agent-skills", "sourceType": "github", "skillPath": "skills/react-native-skills/SKILL.md", - "computedHash": "2e9088a7333666d8c2833b8ff58bd51b955501c42b4c7244f72b4cbf22dafcc4" + "computedHash": "41d24eafa7c3d82e270439808f7cfbc4d51aeb2d14f2809a2267c16275784d06" } } } diff --git a/plugins/react/.agents/skills/vercel-composition-patterns/metadata.json b/plugins/react/.agents/skills/vercel-composition-patterns/metadata.json new file mode 100644 index 00000000..3470b744 --- /dev/null +++ b/plugins/react/.agents/skills/vercel-composition-patterns/metadata.json @@ -0,0 +1,11 @@ +{ + "version": "1.0.0", + "organization": "Engineering", + "date": "January 2026", + "abstract": "Composition patterns for building flexible, maintainable React components. Avoid boolean prop proliferation by using compound components, lifting state, and composing internals. These patterns make codebases easier for both humans and AI agents to work with as they scale.", + "references": [ + "https://react.dev", + "https://react.dev/learn/passing-data-deeply-with-context", + "https://react.dev/reference/react/use" + ] +} diff --git a/plugins/react/.agents/skills/vercel-react-best-practices/metadata.json b/plugins/react/.agents/skills/vercel-react-best-practices/metadata.json new file mode 100644 index 00000000..3bec38b1 --- /dev/null +++ b/plugins/react/.agents/skills/vercel-react-best-practices/metadata.json @@ -0,0 +1,15 @@ +{ + "version": "1.0.0", + "organization": "Vercel Engineering", + "date": "January 2026", + "abstract": "Comprehensive performance optimization guide for React and Next.js applications, designed for AI agents and LLMs. Contains 40+ rules across 8 categories, prioritized by impact from critical (eliminating waterfalls, reducing bundle size) to incremental (advanced patterns). Each rule includes detailed explanations, real-world examples comparing incorrect vs. correct implementations, and specific impact metrics to guide automated refactoring and code generation.", + "references": [ + "https://react.dev", + "https://nextjs.org", + "https://swr.vercel.app", + "https://github.com/shuding/better-all", + "https://github.com/isaacs/node-lru-cache", + "https://vercel.com/blog/how-we-optimized-package-imports-in-next-js", + "https://vercel.com/blog/how-we-made-the-vercel-dashboard-twice-as-fast" + ] +} diff --git a/plugins/react/.agents/skills/vercel-react-view-transitions/metadata.json b/plugins/react/.agents/skills/vercel-react-view-transitions/metadata.json new file mode 100644 index 00000000..aabe3e14 --- /dev/null +++ b/plugins/react/.agents/skills/vercel-react-view-transitions/metadata.json @@ -0,0 +1,12 @@ +{ + "version": "1.0.0", + "organization": "Vercel Engineering", + "date": "March 2026", + "abstract": "Guide for implementing smooth, native-feeling animations using React's View Transition API. Covers the component, addTransitionType, CSS view transition pseudo-elements, shared element transitions, JavaScript animations via Web Animations API, and Next.js integration including the transitionTypes prop on next/link. Includes ready-to-use CSS animation recipes and real-world patterns from production Next.js apps.", + "references": [ + "https://react.dev/reference/react/ViewTransition", + "https://react.dev/reference/react/addTransitionType", + "https://nextjs.org/docs/app/api-reference/config/next-config-js/viewTransition", + "https://github.com/vercel/next-app-router-playground/tree/main/app/view-transitions" + ] +} diff --git a/plugins/react/agent/skills/vercel-composition-patterns/metadata.json b/plugins/react/agent/skills/vercel-composition-patterns/metadata.json new file mode 100644 index 00000000..3470b744 --- /dev/null +++ b/plugins/react/agent/skills/vercel-composition-patterns/metadata.json @@ -0,0 +1,11 @@ +{ + "version": "1.0.0", + "organization": "Engineering", + "date": "January 2026", + "abstract": "Composition patterns for building flexible, maintainable React components. Avoid boolean prop proliferation by using compound components, lifting state, and composing internals. These patterns make codebases easier for both humans and AI agents to work with as they scale.", + "references": [ + "https://react.dev", + "https://react.dev/learn/passing-data-deeply-with-context", + "https://react.dev/reference/react/use" + ] +} diff --git a/plugins/react/agent/skills/vercel-react-best-practices/metadata.json b/plugins/react/agent/skills/vercel-react-best-practices/metadata.json new file mode 100644 index 00000000..3bec38b1 --- /dev/null +++ b/plugins/react/agent/skills/vercel-react-best-practices/metadata.json @@ -0,0 +1,15 @@ +{ + "version": "1.0.0", + "organization": "Vercel Engineering", + "date": "January 2026", + "abstract": "Comprehensive performance optimization guide for React and Next.js applications, designed for AI agents and LLMs. Contains 40+ rules across 8 categories, prioritized by impact from critical (eliminating waterfalls, reducing bundle size) to incremental (advanced patterns). Each rule includes detailed explanations, real-world examples comparing incorrect vs. correct implementations, and specific impact metrics to guide automated refactoring and code generation.", + "references": [ + "https://react.dev", + "https://nextjs.org", + "https://swr.vercel.app", + "https://github.com/shuding/better-all", + "https://github.com/isaacs/node-lru-cache", + "https://vercel.com/blog/how-we-optimized-package-imports-in-next-js", + "https://vercel.com/blog/how-we-made-the-vercel-dashboard-twice-as-fast" + ] +} diff --git a/plugins/react/agent/skills/vercel-react-view-transitions/metadata.json b/plugins/react/agent/skills/vercel-react-view-transitions/metadata.json new file mode 100644 index 00000000..aabe3e14 --- /dev/null +++ b/plugins/react/agent/skills/vercel-react-view-transitions/metadata.json @@ -0,0 +1,12 @@ +{ + "version": "1.0.0", + "organization": "Vercel Engineering", + "date": "March 2026", + "abstract": "Guide for implementing smooth, native-feeling animations using React's View Transition API. Covers the component, addTransitionType, CSS view transition pseudo-elements, shared element transitions, JavaScript animations via Web Animations API, and Next.js integration including the transitionTypes prop on next/link. Includes ready-to-use CSS animation recipes and real-world patterns from production Next.js apps.", + "references": [ + "https://react.dev/reference/react/ViewTransition", + "https://react.dev/reference/react/addTransitionType", + "https://nextjs.org/docs/app/api-reference/config/next-config-js/viewTransition", + "https://github.com/vercel/next-app-router-playground/tree/main/app/view-transitions" + ] +} diff --git a/plugins/react/skills-lock.json b/plugins/react/skills-lock.json index ccddbef6..3344fc5e 100644 --- a/plugins/react/skills-lock.json +++ b/plugins/react/skills-lock.json @@ -5,19 +5,19 @@ "source": "vercel-labs/agent-skills", "sourceType": "github", "skillPath": "skills/composition-patterns/SKILL.md", - "computedHash": "f98931159fa9c7fed043bcd18a891a46dcf89ababa38df13a4c5b7b30dc0ce07" + "computedHash": "575757e3e25761c8c562d6e395d29f0b76c98b1273c0bd72d88e6ab1bc9c7d42" }, "vercel-react-best-practices": { "source": "vercel-labs/agent-skills", "sourceType": "github", "skillPath": "skills/react-best-practices/SKILL.md", - "computedHash": "3219a1944e404ffc14d1d9d6aef6dd2e3855b81387ee0a044ccbfe14d34c2357" + "computedHash": "ca7b0c0c6e5f2750043f7f0cd72d16ac4e2abc48f9b5500d047a4b77a2506212" }, "vercel-react-view-transitions": { "source": "vercel-labs/agent-skills", "sourceType": "github", "skillPath": "skills/react-view-transitions/SKILL.md", - "computedHash": "73fddafed488c308ee0799178432801fe10aa338451948ea05f4200541053040" + "computedHash": "2033ef20681c90d4f93deee719e55e019c254e496d9bf80381c27cc539292001" } } } diff --git a/plugins/slidev/.agents/skills/slidev/references/code-magic-move.md b/plugins/slidev/.agents/skills/slidev/references/code-magic-move.md index a490da39..79c2ae8a 100644 --- a/plugins/slidev/.agents/skills/slidev/references/code-magic-move.md +++ b/plugins/slidev/.agents/skills/slidev/references/code-magic-move.md @@ -45,6 +45,19 @@ const add = () => count += 1 ```` ````` +## Animation Options + +Customize duration globally with `magicMoveDuration` (ms, headmatter). Fine-tune easing, stagger, delays, and diffing behavior via `shiki.magicMove` (headmatter), which is passed through to [Shiki Magic Move](https://shiki.style/packages/magic-move#options): + +```yaml +--- +shiki: + magicMove: + easing: ease-in-out + stagger: 5 +--- +``` + ## How It Works - Wraps multiple code blocks as one diff --git a/plugins/slidev/.agents/skills/slidev/references/core-cli.md b/plugins/slidev/.agents/skills/slidev/references/core-cli.md index d29aa322..4b68f803 100644 --- a/plugins/slidev/.agents/skills/slidev/references/core-cli.md +++ b/plugins/slidev/.agents/skills/slidev/references/core-cli.md @@ -65,7 +65,7 @@ Options: | Option | Default | Description | |--------|---------|-------------| | `--output` | - | Output filename | -| `--format` | pdf | pdf / png / pptx / md | +| `--format` | pdf | pdf / png / pptx / pptx-editable / md | | `--timeout` | 30000 | Timeout per slide (ms) | | `--range` | - | Slide range (e.g., 1,4-7) | | `--dark` | false | Export dark mode | diff --git a/plugins/slidev/.agents/skills/slidev/references/core-exporting.md b/plugins/slidev/.agents/skills/slidev/references/core-exporting.md index 17cfea1e..846464b5 100644 --- a/plugins/slidev/.agents/skills/slidev/references/core-exporting.md +++ b/plugins/slidev/.agents/skills/slidev/references/core-exporting.md @@ -30,9 +30,12 @@ slidev export --output my-slides.pdf ### PowerPoint Export ```bash -slidev export --format pptx +slidev export --format pptx # each slide as an image +slidev export --format pptx-editable # native shapes, selectable text ``` +`pptx-editable` measures the rendered slides and rebuilds them as PowerPoint shapes. SVG (including Mermaid), canvas, iframes, KaTeX formulas, gradients and CSS filters stay pictures, and any slide that cannot be rebuilt falls back to the image export on its own. Fonts are named, not embedded. `--per-slide` is not supported with it. + ### PNG Export ```bash diff --git a/plugins/slidev/agent/skills/slidev/references/code-magic-move.md b/plugins/slidev/agent/skills/slidev/references/code-magic-move.md index a490da39..79c2ae8a 100644 --- a/plugins/slidev/agent/skills/slidev/references/code-magic-move.md +++ b/plugins/slidev/agent/skills/slidev/references/code-magic-move.md @@ -45,6 +45,19 @@ const add = () => count += 1 ```` ````` +## Animation Options + +Customize duration globally with `magicMoveDuration` (ms, headmatter). Fine-tune easing, stagger, delays, and diffing behavior via `shiki.magicMove` (headmatter), which is passed through to [Shiki Magic Move](https://shiki.style/packages/magic-move#options): + +```yaml +--- +shiki: + magicMove: + easing: ease-in-out + stagger: 5 +--- +``` + ## How It Works - Wraps multiple code blocks as one diff --git a/plugins/slidev/agent/skills/slidev/references/core-cli.md b/plugins/slidev/agent/skills/slidev/references/core-cli.md index d29aa322..4b68f803 100644 --- a/plugins/slidev/agent/skills/slidev/references/core-cli.md +++ b/plugins/slidev/agent/skills/slidev/references/core-cli.md @@ -65,7 +65,7 @@ Options: | Option | Default | Description | |--------|---------|-------------| | `--output` | - | Output filename | -| `--format` | pdf | pdf / png / pptx / md | +| `--format` | pdf | pdf / png / pptx / pptx-editable / md | | `--timeout` | 30000 | Timeout per slide (ms) | | `--range` | - | Slide range (e.g., 1,4-7) | | `--dark` | false | Export dark mode | diff --git a/plugins/slidev/agent/skills/slidev/references/core-exporting.md b/plugins/slidev/agent/skills/slidev/references/core-exporting.md index 17cfea1e..846464b5 100644 --- a/plugins/slidev/agent/skills/slidev/references/core-exporting.md +++ b/plugins/slidev/agent/skills/slidev/references/core-exporting.md @@ -30,9 +30,12 @@ slidev export --output my-slides.pdf ### PowerPoint Export ```bash -slidev export --format pptx +slidev export --format pptx # each slide as an image +slidev export --format pptx-editable # native shapes, selectable text ``` +`pptx-editable` measures the rendered slides and rebuilds them as PowerPoint shapes. SVG (including Mermaid), canvas, iframes, KaTeX formulas, gradients and CSS filters stay pictures, and any slide that cannot be rebuilt falls back to the image export on its own. Fonts are named, not embedded. `--per-slide` is not supported with it. + ### PNG Export ```bash diff --git a/plugins/slidev/skills-lock.json b/plugins/slidev/skills-lock.json index b9237e93..0f1e7436 100644 --- a/plugins/slidev/skills-lock.json +++ b/plugins/slidev/skills-lock.json @@ -5,7 +5,7 @@ "source": "slidevjs/slidev", "sourceType": "github", "skillPath": "skills/slidev/SKILL.md", - "computedHash": "a40d5717b0c1db90db946a40f2a258c248779bc933eb9a9bc6fb1f90b4cc0a05" + "computedHash": "745f8fbe6bd26c17699efff608548560e6d4b5ca65dbcff70d394f9d6f6374aa" } } } diff --git a/plugins/turborepo/.agents/skills/turborepo/SKILL.md b/plugins/turborepo/.agents/skills/turborepo/SKILL.md index 930243f2..19b1bd9e 100644 --- a/plugins/turborepo/.agents/skills/turborepo/SKILL.md +++ b/plugins/turborepo/.agents/skills/turborepo/SKILL.md @@ -9,7 +9,7 @@ description: | monorepo, shares code between apps, runs changed/affected packages, debugs cache, or has apps/packages directories. metadata: - version: 2.10.13-canary.6 + version: 2.11.2 --- # Turborepo Skill @@ -740,7 +740,7 @@ import { Button } from "@repo/ui/button"; ```json { - "$schema": "https://v2-10-13-canary-6.turborepo.dev/schema.json", + "$schema": "https://v2-11-2.turborepo.dev/schema.json", "tasks": { "build": { "dependsOn": ["^build"], diff --git a/plugins/turborepo/.agents/skills/turborepo/references/best-practices/structure.md b/plugins/turborepo/.agents/skills/turborepo/references/best-practices/structure.md index 56fafd86..da76258e 100644 --- a/plugins/turborepo/.agents/skills/turborepo/references/best-practices/structure.md +++ b/plugins/turborepo/.agents/skills/turborepo/references/best-practices/structure.md @@ -106,7 +106,7 @@ Package tasks enable Turborepo to: ```json { - "$schema": "https://v2-10-13-canary-6.turborepo.dev/schema.json", + "$schema": "https://v2-11-2.turborepo.dev/schema.json", "tasks": { "build": { "dependsOn": ["^build"], @@ -128,7 +128,7 @@ With `futureFlags.globalConfiguration`, global settings move under a `global` ke ```json { - "$schema": "https://v2-10-13-canary-6.turborepo.dev/schema.json", + "$schema": "https://v2-11-2.turborepo.dev/schema.json", "futureFlags": { "globalConfiguration": true }, "global": { "inputs": ["tsconfig.json"], diff --git a/plugins/turborepo/.agents/skills/turborepo/references/configuration/RULE.md b/plugins/turborepo/.agents/skills/turborepo/references/configuration/RULE.md index b9115879..a1667e0a 100644 --- a/plugins/turborepo/.agents/skills/turborepo/references/configuration/RULE.md +++ b/plugins/turborepo/.agents/skills/turborepo/references/configuration/RULE.md @@ -73,7 +73,7 @@ When you run `turbo run lint`, Turborepo finds all packages with a `lint` script ```json { - "$schema": "https://v2-10-13-canary-6.turborepo.dev/schema.json", + "$schema": "https://v2-11-2.turborepo.dev/schema.json", "globalEnv": ["CI"], "globalDependencies": ["tsconfig.json"], "tasks": { @@ -97,7 +97,7 @@ When the `globalConfiguration` future flag is enabled, global options move under ```json { - "$schema": "https://v2-10-13-canary-6.turborepo.dev/schema.json", + "$schema": "https://v2-11-2.turborepo.dev/schema.json", "futureFlags": { "globalConfiguration": true }, "global": { "inputs": ["tsconfig.json"], diff --git a/plugins/turborepo/.agents/skills/turborepo/references/configuration/tasks.md b/plugins/turborepo/.agents/skills/turborepo/references/configuration/tasks.md index dffe71f7..50c678c1 100644 --- a/plugins/turborepo/.agents/skills/turborepo/references/configuration/tasks.md +++ b/plugins/turborepo/.agents/skills/turborepo/references/configuration/tasks.md @@ -2,6 +2,30 @@ Full docs: https://turborepo.dev/docs/reference/configuration#tasks +## command (Experimental) + +Native toolchain integrations provide fixed built-in task names, such as `build`, `test`, `lint`, `format`, and `dev`. The intended escape hatch for a different task name or a command override is the experimental `command` field. Enable `experimentalTaskCommand` in the root `turbo.json` before using it. + +For an unscoped root task, use a per-toolchain command map. Each value is an argument array that runs directly without a shell: + +```json +{ + "futureFlags": { + "experimentalGoWorkspaces": true, + "experimentalTaskCommand": true + }, + "tasks": { + "test": { + "command": { + "go": ["go", "test", "-race", "./..."] + } + } + } +} +``` + +The supported toolchain keys are `javascript`, `rust`, `python`, and `go` (`typescript` is an alias for `javascript`). Native Rust, Python, and Go keys also require their corresponding workspace Future Flag. The map form is only valid for unscoped tasks in the root configuration; for a package-scoped task or Package Configuration, set `command` directly to an argument array. + ## dependsOn Controls task execution order. diff --git a/plugins/turborepo/.agents/skills/turborepo/references/environment/RULE.md b/plugins/turborepo/.agents/skills/turborepo/references/environment/RULE.md index 12a724c4..9f86c448 100644 --- a/plugins/turborepo/.agents/skills/turborepo/references/environment/RULE.md +++ b/plugins/turborepo/.agents/skills/turborepo/references/environment/RULE.md @@ -107,7 +107,7 @@ When the `globalConfiguration` future flag is enabled, global environment keys m ```json { - "$schema": "https://v2-10-13-canary-6.turborepo.dev/schema.json", + "$schema": "https://v2-11-2.turborepo.dev/schema.json", "globalEnv": ["CI", "NODE_ENV"], "globalPassThroughEnv": ["GITHUB_TOKEN", "NPM_TOKEN"], "tasks": { diff --git a/plugins/turborepo/.agents/skills/turborepo/references/environment/gotchas.md b/plugins/turborepo/.agents/skills/turborepo/references/environment/gotchas.md index f0c4b3d6..45bdc5d9 100644 --- a/plugins/turborepo/.agents/skills/turborepo/references/environment/gotchas.md +++ b/plugins/turborepo/.agents/skills/turborepo/references/environment/gotchas.md @@ -112,7 +112,7 @@ If you use `.env.development` and `.env.production`, both should be in inputs. ```json { - "$schema": "https://v2-10-13-canary-6.turborepo.dev/schema.json", + "$schema": "https://v2-11-2.turborepo.dev/schema.json", "globalEnv": ["CI", "NODE_ENV", "VERCEL"], "globalPassThroughEnv": ["GITHUB_TOKEN", "VERCEL_URL"], "tasks": { @@ -146,7 +146,7 @@ The same config using the `global` key. The `.env` files move to `global.inputs` ```json { - "$schema": "https://v2-10-13-canary-6.turborepo.dev/schema.json", + "$schema": "https://v2-11-2.turborepo.dev/schema.json", "futureFlags": { "globalConfiguration": true }, "global": { "env": ["CI", "NODE_ENV", "VERCEL"], diff --git a/plugins/turborepo/agent/skills/turborepo/SKILL.md b/plugins/turborepo/agent/skills/turborepo/SKILL.md index 95e35770..8022632d 100644 --- a/plugins/turborepo/agent/skills/turborepo/SKILL.md +++ b/plugins/turborepo/agent/skills/turborepo/SKILL.md @@ -18,7 +18,7 @@ description: > or has apps/packages directories. metadata: - version: 2.10.13-canary.6 + version: 2.11.2 --- # Turborepo Skill @@ -748,7 +748,7 @@ import { Button } from "@repo/ui/button"; ```json { - "$schema": "https://v2-10-13-canary-6.turborepo.dev/schema.json", + "$schema": "https://v2-11-2.turborepo.dev/schema.json", "tasks": { "build": { "dependsOn": ["^build"], diff --git a/plugins/turborepo/agent/skills/turborepo/references/best-practices/structure.md b/plugins/turborepo/agent/skills/turborepo/references/best-practices/structure.md index 56fafd86..da76258e 100644 --- a/plugins/turborepo/agent/skills/turborepo/references/best-practices/structure.md +++ b/plugins/turborepo/agent/skills/turborepo/references/best-practices/structure.md @@ -106,7 +106,7 @@ Package tasks enable Turborepo to: ```json { - "$schema": "https://v2-10-13-canary-6.turborepo.dev/schema.json", + "$schema": "https://v2-11-2.turborepo.dev/schema.json", "tasks": { "build": { "dependsOn": ["^build"], @@ -128,7 +128,7 @@ With `futureFlags.globalConfiguration`, global settings move under a `global` ke ```json { - "$schema": "https://v2-10-13-canary-6.turborepo.dev/schema.json", + "$schema": "https://v2-11-2.turborepo.dev/schema.json", "futureFlags": { "globalConfiguration": true }, "global": { "inputs": ["tsconfig.json"], diff --git a/plugins/turborepo/agent/skills/turborepo/references/configuration/RULE.md b/plugins/turborepo/agent/skills/turborepo/references/configuration/RULE.md index b9115879..a1667e0a 100644 --- a/plugins/turborepo/agent/skills/turborepo/references/configuration/RULE.md +++ b/plugins/turborepo/agent/skills/turborepo/references/configuration/RULE.md @@ -73,7 +73,7 @@ When you run `turbo run lint`, Turborepo finds all packages with a `lint` script ```json { - "$schema": "https://v2-10-13-canary-6.turborepo.dev/schema.json", + "$schema": "https://v2-11-2.turborepo.dev/schema.json", "globalEnv": ["CI"], "globalDependencies": ["tsconfig.json"], "tasks": { @@ -97,7 +97,7 @@ When the `globalConfiguration` future flag is enabled, global options move under ```json { - "$schema": "https://v2-10-13-canary-6.turborepo.dev/schema.json", + "$schema": "https://v2-11-2.turborepo.dev/schema.json", "futureFlags": { "globalConfiguration": true }, "global": { "inputs": ["tsconfig.json"], diff --git a/plugins/turborepo/agent/skills/turborepo/references/configuration/tasks.md b/plugins/turborepo/agent/skills/turborepo/references/configuration/tasks.md index dffe71f7..50c678c1 100644 --- a/plugins/turborepo/agent/skills/turborepo/references/configuration/tasks.md +++ b/plugins/turborepo/agent/skills/turborepo/references/configuration/tasks.md @@ -2,6 +2,30 @@ Full docs: https://turborepo.dev/docs/reference/configuration#tasks +## command (Experimental) + +Native toolchain integrations provide fixed built-in task names, such as `build`, `test`, `lint`, `format`, and `dev`. The intended escape hatch for a different task name or a command override is the experimental `command` field. Enable `experimentalTaskCommand` in the root `turbo.json` before using it. + +For an unscoped root task, use a per-toolchain command map. Each value is an argument array that runs directly without a shell: + +```json +{ + "futureFlags": { + "experimentalGoWorkspaces": true, + "experimentalTaskCommand": true + }, + "tasks": { + "test": { + "command": { + "go": ["go", "test", "-race", "./..."] + } + } + } +} +``` + +The supported toolchain keys are `javascript`, `rust`, `python`, and `go` (`typescript` is an alias for `javascript`). Native Rust, Python, and Go keys also require their corresponding workspace Future Flag. The map form is only valid for unscoped tasks in the root configuration; for a package-scoped task or Package Configuration, set `command` directly to an argument array. + ## dependsOn Controls task execution order. diff --git a/plugins/turborepo/agent/skills/turborepo/references/environment/RULE.md b/plugins/turborepo/agent/skills/turborepo/references/environment/RULE.md index 12a724c4..9f86c448 100644 --- a/plugins/turborepo/agent/skills/turborepo/references/environment/RULE.md +++ b/plugins/turborepo/agent/skills/turborepo/references/environment/RULE.md @@ -107,7 +107,7 @@ When the `globalConfiguration` future flag is enabled, global environment keys m ```json { - "$schema": "https://v2-10-13-canary-6.turborepo.dev/schema.json", + "$schema": "https://v2-11-2.turborepo.dev/schema.json", "globalEnv": ["CI", "NODE_ENV"], "globalPassThroughEnv": ["GITHUB_TOKEN", "NPM_TOKEN"], "tasks": { diff --git a/plugins/turborepo/agent/skills/turborepo/references/environment/gotchas.md b/plugins/turborepo/agent/skills/turborepo/references/environment/gotchas.md index f0c4b3d6..45bdc5d9 100644 --- a/plugins/turborepo/agent/skills/turborepo/references/environment/gotchas.md +++ b/plugins/turborepo/agent/skills/turborepo/references/environment/gotchas.md @@ -112,7 +112,7 @@ If you use `.env.development` and `.env.production`, both should be in inputs. ```json { - "$schema": "https://v2-10-13-canary-6.turborepo.dev/schema.json", + "$schema": "https://v2-11-2.turborepo.dev/schema.json", "globalEnv": ["CI", "NODE_ENV", "VERCEL"], "globalPassThroughEnv": ["GITHUB_TOKEN", "VERCEL_URL"], "tasks": { @@ -146,7 +146,7 @@ The same config using the `global` key. The `.env` files move to `global.inputs` ```json { - "$schema": "https://v2-10-13-canary-6.turborepo.dev/schema.json", + "$schema": "https://v2-11-2.turborepo.dev/schema.json", "futureFlags": { "globalConfiguration": true }, "global": { "env": ["CI", "NODE_ENV", "VERCEL"], diff --git a/plugins/turborepo/skills-lock.json b/plugins/turborepo/skills-lock.json index 4577044f..e9a4b44e 100644 --- a/plugins/turborepo/skills-lock.json +++ b/plugins/turborepo/skills-lock.json @@ -5,7 +5,7 @@ "source": "vercel/turborepo", "sourceType": "github", "skillPath": "skills/turborepo/SKILL.md", - "computedHash": "dd8b7e6db379c5455c7321ea64581b357e0af30a8302afab37dc7be8e519966d" + "computedHash": "fb06bed05c194cc42f7292f996676254e25080aebaaed613ad3cb0591645e1b0" } } } diff --git a/plugins/vercel-sandbox/skills-lock.json b/plugins/vercel-sandbox/skills-lock.json index 134383d7..3c553caa 100644 --- a/plugins/vercel-sandbox/skills-lock.json +++ b/plugins/vercel-sandbox/skills-lock.json @@ -5,7 +5,7 @@ "source": "vercel/sandbox", "sourceType": "github", "skillPath": "skills/sandbox/SKILL.md", - "computedHash": "3328be60e2d4b27ef4de0c69d815e75c5bfa7510d23b7eb8ed3ed8f33b311ae6" + "computedHash": "779275ac0336a7aeb2b3622de58f90bb879b1487c59afad4ebbc6510f4c65e2d" } } } diff --git a/plugins/vueuse/.agents/skills/vueuse-functions/SKILL.md b/plugins/vueuse/.agents/skills/vueuse-functions/SKILL.md index cdfad1fc..1c4c6225 100644 --- a/plugins/vueuse/.agents/skills/vueuse-functions/SKILL.md +++ b/plugins/vueuse/.agents/skills/vueuse-functions/SKILL.md @@ -93,6 +93,7 @@ IMPORTANT: Each function entry includes a short `Description` and a detailed `Re | [`useFullscreen`](references/useFullscreen.md) | Reactive [Fullscreen API](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API) | AUTO | | [`useGamepad`](references/useGamepad.md) | Provides reactive bindings for the [Gamepad API](https://developer.mozilla.org/en-US/docs/Web/API/Gamepad_API) | AUTO | | [`useImage`](references/useImage.md) | Reactive load an image in the browser | AUTO | +| [`useLiveAnnouncer`](references/useLiveAnnouncer.md) | Accessible way to announce messages to screen reader users (ARIA live regions) | AUTO | | [`useMediaControls`](references/useMediaControls.md) | Reactive media controls for both `audio` and `video` elements | AUTO | | [`useMediaQuery`](references/useMediaQuery.md) | Reactive [Media Query](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Testing_media_queries) | AUTO | | [`useMemory`](references/useMemory.md) | Reactive Memory Info | AUTO | @@ -117,6 +118,7 @@ IMPORTANT: Each function entry includes a short `Description` and a detailed `Re | [`useUrlSearchParams`](references/useUrlSearchParams.md) | Reactive [URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) | AUTO | | [`useVibrate`](references/useVibrate.md) | Reactive [Vibration API](https://developer.mozilla.org/en-US/docs/Web/API/Vibration_API) | AUTO | | [`useWakeLock`](references/useWakeLock.md) | Reactive [Screen Wake Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Screen_Wake_Lock_API) | AUTO | +| [`useWebMCP`](references/useWebMCP.md) | Register a [WebMCP](https://github.com/webmachinelearning/webmcp) tool and tie its lifecycle to the current Vue scope | AUTO | | [`useWebNotification`](references/useWebNotification.md) | Reactive [Notification](https://developer.mozilla.org/en-US/docs/Web/API/notification) | AUTO | | [`useWebWorker`](references/useWebWorker.md) | Simple [Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) registration and communication | AUTO | | [`useWebWorkerFn`](references/useWebWorkerFn.md) | Run expensive functions without blocking the UI | AUTO | @@ -193,7 +195,6 @@ IMPORTANT: Each function entry includes a short `Description` and a detailed `Re | [`computedInject`](references/computedInject.md) | Combine `computed` and `inject` | AUTO | | [`createReusableTemplate`](references/createReusableTemplate.md) | Define and reuse template inside the component scope | AUTO | | [`createTemplatePromise`](references/createTemplatePromise.md) | Template as Promise | AUTO | -| [`templateRef`](references/templateRef.md) | Shorthand for binding ref to template element | AUTO | | [`tryOnBeforeMount`](references/tryOnBeforeMount.md) | Safe `onBeforeMount` | AUTO | | [`tryOnBeforeUnmount`](references/tryOnBeforeUnmount.md) | Safe `onBeforeUnmount` | AUTO | | [`tryOnMounted`](references/tryOnMounted.md) | Safe `onMounted` | AUTO | @@ -275,6 +276,7 @@ IMPORTANT: Each function entry includes a short `Description` and a detailed `Re |----------|-------------|------------| | [`useCountdown`](references/useCountdown.md) | Reactive countdown timer in seconds | AUTO | | [`useDateFormat`](references/useDateFormat.md) | Get the formatted date according to the string of tokens passed in | AUTO | +| [`useTemporalNow`](references/useTemporalNow.md) | Reactive [Temporal API](https://tc39.es/proposal-temporal/docs/) with timezone conversion and calendar system support | AUTO | | [`useTimeAgo`](references/useTimeAgo.md) | Reactive time ago | AUTO | | [`useTimeAgoIntl`](references/useTimeAgoIntl.md) | Reactive time ago with i18n supported | AUTO | diff --git a/plugins/vueuse/.agents/skills/vueuse-functions/references/injectLocal.md b/plugins/vueuse/.agents/skills/vueuse-functions/references/injectLocal.md index 165acb30..3ac2f1a0 100644 --- a/plugins/vueuse/.agents/skills/vueuse-functions/references/injectLocal.md +++ b/plugins/vueuse/.agents/skills/vueuse-functions/references/injectLocal.md @@ -29,7 +29,7 @@ const injectedValue = injectLocal('MyInjectionKey') // injectedValue === 1 * const injectedValue = injectLocal('MyInjectionKey') // injectedValue === 1 * ``` * - * @__NO_SIDE_EFFECTS__ + * @NO_SIDE_EFFECTS */ export declare const injectLocal: typeof inject ``` diff --git a/plugins/vueuse/.agents/skills/vueuse-functions/references/useBreakpoints.md b/plugins/vueuse/.agents/skills/vueuse-functions/references/useBreakpoints.md index 13caff9d..df8b21b4 100644 --- a/plugins/vueuse/.agents/skills/vueuse-functions/references/useBreakpoints.md +++ b/plugins/vueuse/.agents/skills/vueuse-functions/references/useBreakpoints.md @@ -90,7 +90,7 @@ const breakpoints = useBreakpoints(breakpointsTailwind, { #### Server Side Rendering and Nuxt -If you are using `useBreakpoints` with SSR enabled, then you need to specify which screen size you would like to render on the server and before hydration to avoid an hydration mismatch +If you are using `useBreakpoints` with SSR enabled, then you need to specify which screen size you would like to render on the server and before hydration to avoid a hydration mismatch ```ts import { breakpointsTailwind, useBreakpoints } from '@vueuse/core' diff --git a/plugins/vueuse/.agents/skills/vueuse-functions/references/useCloned.md b/plugins/vueuse/.agents/skills/vueuse-functions/references/useCloned.md index f48c19e2..22ce00a5 100644 --- a/plugins/vueuse/.agents/skills/vueuse-functions/references/useCloned.md +++ b/plugins/vueuse/.agents/skills/vueuse-functions/references/useCloned.md @@ -97,6 +97,6 @@ export type CloneFn = (x: F) => T export declare function cloneFnJSON(source: T): T export declare function useCloned( source: MaybeRefOrGetter, - options?: UseClonedOptions, + options?: UseClonedOptions, ): UseClonedReturn ``` diff --git a/plugins/vueuse/.agents/skills/vueuse-functions/references/useCountdown.md b/plugins/vueuse/.agents/skills/vueuse-functions/references/useCountdown.md index ac6734b1..79cf396a 100644 --- a/plugins/vueuse/.agents/skills/vueuse-functions/references/useCountdown.md +++ b/plugins/vueuse/.agents/skills/vueuse-functions/references/useCountdown.md @@ -50,12 +50,6 @@ start() ```ts export interface UseCountdownOptions extends ConfigurableScheduler { - /** - * Interval for the countdown in milliseconds. Default is 1000ms. - * - * @deprecated Please use `scheduler` option instead - */ - interval?: MaybeRefOrGetter /** * Callback function called when the countdown reaches 0. */ @@ -64,13 +58,6 @@ export interface UseCountdownOptions extends ConfigurableScheduler { * Callback function called on each tick of the countdown. */ onTick?: () => void - /** - * Start the countdown immediately - * - * @deprecated Please use `scheduler` option instead - * @default false - */ - immediate?: boolean } export interface UseCountdownReturn extends Pausable { /** diff --git a/plugins/vueuse/.agents/skills/vueuse-functions/references/useElementByPoint.md b/plugins/vueuse/.agents/skills/vueuse-functions/references/useElementByPoint.md index 9c8326a9..9dc3032a 100644 --- a/plugins/vueuse/.agents/skills/vueuse-functions/references/useElementByPoint.md +++ b/plugins/vueuse/.agents/skills/vueuse-functions/references/useElementByPoint.md @@ -23,10 +23,6 @@ export interface UseElementByPointOptions x: MaybeRefOrGetter y: MaybeRefOrGetter multiple?: MaybeRefOrGetter - /** @deprecated Please use `scheduler` option instead */ - immediate?: boolean - /** @deprecated Please use `scheduler` option instead */ - interval?: "requestAnimationFrame" | number } export interface UseElementByPointReturn extends Supportable, Pausable { diff --git a/plugins/vueuse/.agents/skills/vueuse-functions/references/useIDBKeyval.md b/plugins/vueuse/.agents/skills/vueuse-functions/references/useIDBKeyval.md index d27595ae..5ed8c1e0 100644 --- a/plugins/vueuse/.agents/skills/vueuse-functions/references/useIDBKeyval.md +++ b/plugins/vueuse/.agents/skills/vueuse-functions/references/useIDBKeyval.md @@ -37,6 +37,15 @@ console.log('IDB transaction finished!') storedObject.value = null ``` +## Cross-tab syncing + +Changes are automatically synced across browser tabs using the [`BroadcastChannel` API](https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel). This is enabled by default and can be disabled via the `listenToStorageChanges` option. + +```ts +// disable cross-tab syncing +const { data } = useIDBKeyval('my-key', 'default', { listenToStorageChanges: false }) +``` + ## Type Declarations ```ts @@ -44,7 +53,8 @@ interface Serializer { read: (raw: unknown) => T write: (value: T) => unknown } -export interface UseIDBOptions extends ConfigurableFlush { +export interface UseIDBOptions + extends ConfigurableFlush, ConfigurableWindow { /** * Watch for deep changes * @@ -73,10 +83,18 @@ export interface UseIDBOptions extends ConfigurableFlush { * Custom data serialization */ serializer?: Serializer + /** + * Listen to storage changes from other tabs via BroadcastChannel, + * useful for multiple tabs applications + * + * @default true + */ + listenToStorageChanges?: boolean } export interface UseIDBKeyvalReturn { data: RemovableRef isFinished: ShallowRef + isSupported: ComputedRef set: (value: T) => Promise } /** diff --git a/plugins/vueuse/.agents/skills/vueuse-functions/references/useIntersectionObserver.md b/plugins/vueuse/.agents/skills/vueuse-functions/references/useIntersectionObserver.md index 23ca821e..71cc66b7 100644 --- a/plugins/vueuse/.agents/skills/vueuse-functions/references/useIntersectionObserver.md +++ b/plugins/vueuse/.agents/skills/vueuse-functions/references/useIntersectionObserver.md @@ -31,6 +31,34 @@ const { stop } = useIntersectionObserver( ``` +### Controls and cleanup + +`useIntersectionObserver` returns controls for the underlying observer: + +| State | Type | Description | +| ------------- | ---------------------- | ------------------------------------------------------------------------------------- | +| `isSupported` | `ComputedRef` | Whether the `IntersectionObserver` API is available. | +| `isActive` | `ShallowRef` | Whether the observer is currently running. Turns `false` after `pause()` or `stop()`. | +| `pause` | `() => void` | Pause observing and set `isActive` to `false`. | +| `resume` | `() => void` | Resume observing. | +| `stop` | `() => void` | Stop observing permanently. | + +The observer is disconnected automatically via [`tryOnScopeDispose`](https://vueuse.org/shared/tryOnScopeDispose/) when the component or effect scope that created it is disposed, so in most cases you don't need to call `stop` yourself. Call `stop()` to disconnect the observer earlier, for example once the element has become visible: + +```ts +import { useIntersectionObserver } from '@vueuse/core' +// ---cut--- +const { stop } = useIntersectionObserver( + target, + ([entry]) => { + if (entry?.isIntersecting) { + // react to the element becoming visible once, then stop observing + stop() + } + }, +) +``` + ## Directive Usage ```vue diff --git a/plugins/vueuse/.agents/skills/vueuse-functions/references/useLiveAnnouncer.md b/plugins/vueuse/.agents/skills/vueuse-functions/references/useLiveAnnouncer.md new file mode 100644 index 00000000..1124fe8a --- /dev/null +++ b/plugins/vueuse/.agents/skills/vueuse-functions/references/useLiveAnnouncer.md @@ -0,0 +1,77 @@ +--- +category: Browser +--- + +# useLiveAnnouncer + +Accessible way to announce messages to screen reader users (ARIA live regions). + +## Usage + +```ts +import { useLiveAnnouncer } from '@vueuse/core' + +const { announce, polite, assertive } = useLiveAnnouncer() + +announce('This is a polite announcement') +polite('This is also a polite announcement') +assertive('Important message!') +``` + +The message stays in the live region until it is replaced by the next announcement. Pass a `timeout` (in milliseconds) to automatically clear it after a delay: + +```ts +// clears the message after 3000ms +announce('Saved successfully', 'polite', 3000) +polite('Saved successfully', 3000) +assertive('Network error', 3000) +``` + +## Accessibility + +The announcer uses the following ARIA attributes: + +- **Polite**: `role="status"`, `aria-live="polite"`, `aria-atomic="true"` +- **Assertive**: `role="alert"`, `aria-live="assertive"`, `aria-atomic="true"` + +These ensure robust support across different screen readers. + +## Options + +### idPrefix + +- Type: `string` +- Default: `'vueuse-live-announcer'` + +Prefix for the id of the announcer elements. The generated elements will have IDs `${idPrefix}-container`, `${idPrefix}-polite`, and `${idPrefix}-assertive`. + +### window + +- Type: `Window` +- Default: `defaultWindow` + +The window object where the announcer elements will be created. + +## Type Declarations + +```ts +export interface UseLiveAnnouncerOptions extends ConfigurableWindow { + /** + * The prefix for the id of the announcer elements. + * @default 'vueuse-live-announcer' + */ + idPrefix?: string +} +export interface UseLiveAnnouncerReturn { + announce: ( + message: string, + mode?: "polite" | "assertive", + timeout?: number, + ) => void + polite: (message: string, timeout?: number) => void + assertive: (message: string, timeout?: number) => void +} +export declare function useLiveAnnouncer( + options?: UseLiveAnnouncerOptions, +): UseLiveAnnouncerReturn +``` diff --git a/plugins/vueuse/.agents/skills/vueuse-functions/references/useMediaQuery.md b/plugins/vueuse/.agents/skills/vueuse-functions/references/useMediaQuery.md index fd6a4445..0a5b9c74 100644 --- a/plugins/vueuse/.agents/skills/vueuse-functions/references/useMediaQuery.md +++ b/plugins/vueuse/.agents/skills/vueuse-functions/references/useMediaQuery.md @@ -17,7 +17,7 @@ const isPreferredDark = useMediaQuery('(prefers-color-scheme: dark)') #### Server Side Rendering and Nuxt -If you are using `useMediaQuery` with SSR enabled, then you need to specify which screen size you would like to render on the server and before hydration to avoid an hydration mismatch +If you are using `useMediaQuery` with SSR enabled, then you need to specify which screen size you would like to render on the server and before hydration to avoid a hydration mismatch ```ts import { useMediaQuery } from '@vueuse/core' diff --git a/plugins/vueuse/.agents/skills/vueuse-functions/references/useMemory.md b/plugins/vueuse/.agents/skills/vueuse-functions/references/useMemory.md index 25c09296..48ee5758 100644 --- a/plugins/vueuse/.agents/skills/vueuse-functions/references/useMemory.md +++ b/plugins/vueuse/.agents/skills/vueuse-functions/references/useMemory.md @@ -37,24 +37,7 @@ export interface MemoryInfo { readonly usedJSHeapSize: number [Symbol.toStringTag]: "MemoryInfo" } -export interface UseMemoryOptions extends ConfigurableScheduler { - /** - * Start the timer immediately - * - * @deprecated Please use `scheduler` option instead - * @default true - */ - immediate?: boolean - /** - * Execute the callback immediately after calling `resume` - * - * @deprecated Please use `scheduler` option instead - * @default false - */ - immediateCallback?: boolean - /** @deprecated Please use `scheduler` option instead */ - interval?: number -} +export interface UseMemoryOptions extends ConfigurableScheduler {} export interface UseMemoryReturn extends Supportable { memory: ShallowRef } diff --git a/plugins/vueuse/.agents/skills/vueuse-functions/references/useNow.md b/plugins/vueuse/.agents/skills/vueuse-functions/references/useNow.md index fcc1252c..9e029367 100644 --- a/plugins/vueuse/.agents/skills/vueuse-functions/references/useNow.md +++ b/plugins/vueuse/.agents/skills/vueuse-functions/references/useNow.md @@ -48,20 +48,6 @@ export interface UseNowOptions< * @default false */ controls?: Controls - /** - * Start the clock immediately - * - * @deprecated Please use `scheduler` option instead - * @default true - */ - immediate?: boolean - /** - * Update interval in milliseconds, or use requestAnimationFrame - * - * @deprecated Please use `scheduler` option instead - * @default requestAnimationFrame - */ - interval?: "requestAnimationFrame" | number } export type UseNowReturn = Controls extends true ? { diff --git a/plugins/vueuse/.agents/skills/vueuse-functions/references/usePerformanceObserver.md b/plugins/vueuse/.agents/skills/vueuse-functions/references/usePerformanceObserver.md index d874c9d8..18b31dfd 100644 --- a/plugins/vueuse/.agents/skills/vueuse-functions/references/usePerformanceObserver.md +++ b/plugins/vueuse/.agents/skills/vueuse-functions/references/usePerformanceObserver.md @@ -11,11 +11,11 @@ Observe performance metrics. ```ts import { usePerformanceObserver } from '@vueuse/core' -const entrys = ref([]) +const entries = ref([]) usePerformanceObserver({ entryTypes: ['paint'], }, (list) => { - entrys.value = list.getEntries() + entries.value = list.getEntries() }) ``` diff --git a/plugins/vueuse/.agents/skills/vueuse-functions/references/useRefHistory.md b/plugins/vueuse/.agents/skills/vueuse-functions/references/useRefHistory.md index f47d9fec..57f9eae0 100644 --- a/plugins/vueuse/.agents/skills/vueuse-functions/references/useRefHistory.md +++ b/plugins/vueuse/.agents/skills/vueuse-functions/references/useRefHistory.md @@ -200,7 +200,7 @@ Another option is to avoid mutating the original ref value using `arr.value = [. ## Recommended Readings -- [History and Persistence](https://patak.dev/vue/history-and-persistence.html) - by [@patak-dev](https://github.com/patak-dev) +- [History and Persistence](https://patak.dev/vue/history-and-persistence.html) - by [@patak-cat](https://github.com/patak-cat) ## Type Declarations diff --git a/plugins/vueuse/.agents/skills/vueuse-functions/references/useStepper.md b/plugins/vueuse/.agents/skills/vueuse-functions/references/useStepper.md index e4c20fdd..04ff113d 100644 --- a/plugins/vueuse/.agents/skills/vueuse-functions/references/useStepper.md +++ b/plugins/vueuse/.agents/skills/vueuse-functions/references/useStepper.md @@ -126,6 +126,13 @@ export interface UseStepperReturn { /** Checks if the current step is after the given step. */ isAfter: (step: StepName) => boolean } +/** + * Provides helpers for building a multi-step wizard interface. + * + * @see https://vueuse.org/useStepper + * + * @__NO_SIDE_EFFECTS__ + */ export declare function useStepper( steps: MaybeRef, initialStep?: T, diff --git a/plugins/vueuse/.agents/skills/vueuse-functions/references/useTemporalNow.md b/plugins/vueuse/.agents/skills/vueuse-functions/references/useTemporalNow.md new file mode 100644 index 00000000..73d80e64 --- /dev/null +++ b/plugins/vueuse/.agents/skills/vueuse-functions/references/useTemporalNow.md @@ -0,0 +1,321 @@ +--- +category: Time +--- + +# useTemporalNow + +Reactive [Temporal API](https://tc39.es/proposal-temporal/docs/) with timezone conversion and calendar system support. + +Uses the modern Temporal API instead of the legacy `Date` object, providing better timezone handling, calendar systems, and date/time operations. + +## Requirements + +This function relies on the [`Temporal`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal) API. It does **not** bundle or depend on any Temporal implementation — by default it reads the global `Temporal` object, but you can also pass your own implementation via the `temporal` option. + +- Modern JS engines (recent Node.js, Deno, and browsers) already expose `Temporal` natively, or will soon. +- For environments without native support, install a polyfill yourself, for example [`temporal-polyfill`](https://github.com/fullcalendar/temporal-polyfill): + + ```bash + npm i temporal-polyfill + ``` + + and either load it once as a global, before this function is used (e.g. in your app's entry point): + + ```ts + import 'temporal-polyfill/global' + ``` + + If you need calendar systems beyond `iso8601`/`gregory` (e.g. `islamic`, `hebrew`, `chinese`, `japanese` as used in the examples below), use the `/full/` entry point instead: + + ```ts + import 'temporal-polyfill/full/global' + ``` + + ...or pass it explicitly via the `temporal` option instead of touching the global scope: + + ```ts + import { useTemporalNow } from '@vueuse/core' + import { Temporal } from 'temporal-polyfill' + + const temporal = useTemporalNow({ temporal: Temporal }) + ``` + + [`@js-temporal/polyfill`](https://github.com/js-temporal/temporal-polyfill) is another common alternative. It does not install a global `Temporal` object by itself, so the `temporal` option is the natural way to use it. Its type declarations are authored independently from TypeScript's own ambient `Temporal` types (unlike `temporal-polyfill`, which derives its types from the same source), so a cast is needed to satisfy the `temporal` option at compile time — the runtime objects are spec-compliant and interoperate fine: + + ```ts + import { Temporal } from '@js-temporal/polyfill' + import { useTemporalNow } from '@vueuse/core' + + const temporal = useTemporalNow({ temporal: Temporal as unknown as typeof globalThis.Temporal }) + ``` + +If no `Temporal` implementation can be found (neither passed via the `temporal` option nor available globally), calling `useTemporalNow` will throw an error. + +## Usage + +### Basic Usage + +```vue + + + +``` + +### Timezone Conversion + +```ts +import { useTemporalNow } from '@vueuse/core' + +const temporal = useTemporalNow({ timezone: 'America/New_York' }) + +// Convert to different timezones +const tokyoTime = temporal.toTimezone('Asia/Tokyo') +const londonTime = temporal.toTimezone('Europe/London') +const utcTime = temporal.toTimezone('UTC') + +// Change timezone reactively +temporal.timezone.value = 'Europe/Berlin' +``` + +### Calendar Systems + +```ts +import { useTemporalNow } from '@vueuse/core' + +const temporal = useTemporalNow({ calendar: 'gregory' }) + +// Convert to different calendar systems +const islamicDate = temporal.toCalendar('islamic-umalqura') +const hebrewDate = temporal.toCalendar('hebrew') +const chineseDate = temporal.toCalendar('chinese') + +// Change calendar reactively +temporal.calendar.value = 'islamic-umalqura' +``` + +### Date/Time Manipulation + +```ts +import { useTemporalNow } from '@vueuse/core' + +const { now, add, subtract, compare } = useTemporalNow() + +// Add/subtract durations +const nextWeek = add('P7D') // Add 7 days +const lastMonth = subtract('P1M') // Subtract 1 month +const inTwoHours = add('PT2H') // Add 2 hours + +// Compare dates +const futureDate = add('P1Y') // Add 1 year +const comparison = compare(futureDate) // -1 (now is before futureDate) +``` + +### Format Options + +```ts +import { useTemporalNow } from '@vueuse/core' + +const { format } = useTemporalNow() + +// Different formatting options +const short = format({ dateStyle: 'short' }) // "12/25/23" +const long = format({ dateStyle: 'long' }) // "December 25, 2023" +const time = format({ timeStyle: 'medium' }) // "3:30:00 PM" +const custom = format({ + weekday: 'long', + year: 'numeric', + month: 'long', + day: 'numeric' +}) // "Monday, December 25, 2023" +``` + +### Control Auto-Update + +By default `useTemporalNow` updates on every `requestAnimationFrame`. Pass a +custom `scheduler` to control how updates are driven — for example, tick on a +fixed interval, or start paused: + +```ts +import { useTemporalNow } from '@vueuse/core' +import { useIntervalFn } from '@vueuse/shared' + +const { pause, resume, isActive } = useTemporalNow({ + // Update every 500ms instead of on every animation frame, + // and don't start immediately. + scheduler: cb => useIntervalFn(cb, 500, { immediate: false }), +}) + +// Manually control updates +resume() // Start auto-update +pause() // Stop auto-update + +console.log(isActive.value) // true/false +``` + +## Examples + +### World Clock + +```vue + + + +``` + +### Calendar System Converter + +```vue + + + +``` + +## Type Declarations + +```ts +export interface UseTemporalNowOptions extends ConfigurableScheduler { + /** + * Initial timezone + * + * @default 'UTC' + */ + timezone?: string + /** + * Calendar system to use + * + * @default 'gregory' + */ + calendar?: string + /** + * Custom `Temporal` implementation to use, e.g. the `Temporal` export from + * `@js-temporal/polyfill` or another polyfill, instead of relying on the + * global `Temporal` object. + * + * @default globalThis.Temporal + */ + temporal?: typeof Temporal +} +export interface UseTemporalNowReturn extends Pausable { + /** + * Current `Temporal.ZonedDateTime` + */ + now: Ref + /** + * Current timezone + */ + timezone: Ref + /** + * Current calendar + */ + calendar: Ref + /** + * Convert to a different timezone + */ + toTimezone: (timezone: string) => Temporal.ZonedDateTime + /** + * Convert to a different calendar + */ + toCalendar: (calendar: string) => Temporal.ZonedDateTime + /** + * Get the `Temporal.PlainDate` (date only) + */ + toPlainDate: () => Temporal.PlainDate + /** + * Get the `Temporal.PlainTime` (time only) + */ + toPlainTime: () => Temporal.PlainTime + /** + * Get the `Temporal.PlainDateTime` (local date/time) + */ + toPlainDateTime: () => Temporal.PlainDateTime + /** + * Format the current date/time + */ + format: (options?: Intl.DateTimeFormatOptions) => string + /** + * Add a duration + */ + add: (duration: Temporal.DurationLike) => Temporal.ZonedDateTime + /** + * Subtract a duration + */ + subtract: (duration: Temporal.DurationLike) => Temporal.ZonedDateTime + /** + * Compare with another date/time + */ + compare: (other: Temporal.ZonedDateTime | string) => number +} +/** + * Reactive Temporal API with timezone and calendar support. + * + * @see https://vueuse.org/useTemporalNow + * @param options - Configuration options + */ +export declare function useTemporalNow( + options?: UseTemporalNowOptions, +): UseTemporalNowReturn +``` diff --git a/plugins/vueuse/.agents/skills/vueuse-functions/references/useThrottleFn.md b/plugins/vueuse/.agents/skills/vueuse-functions/references/useThrottleFn.md index 85e22bb0..bc20ae50 100644 --- a/plugins/vueuse/.agents/skills/vueuse-functions/references/useThrottleFn.md +++ b/plugins/vueuse/.agents/skills/vueuse-functions/references/useThrottleFn.md @@ -37,7 +37,7 @@ useEventListener(window, 'resize', throttledFn) * @param ms A zero-or-greater delay in milliseconds. For event callbacks, values around 100 or 250 (or even higher) are most useful. * (default value: 200) * - * @param [trailing] if true, call fn again after the time is up (default value: false) + * @param [trailing] if true, call fn again after the time is up (default value: true) * * @param [leading] if true, call fn on the leading edge of the ms timeout (default value: true) * diff --git a/plugins/vueuse/.agents/skills/vueuse-functions/references/useTimeAgo.md b/plugins/vueuse/.agents/skills/vueuse-functions/references/useTimeAgo.md index 049d60a0..b779bb21 100644 --- a/plugins/vueuse/.agents/skills/vueuse-functions/references/useTimeAgo.md +++ b/plugins/vueuse/.agents/skills/vueuse-functions/references/useTimeAgo.md @@ -99,13 +99,6 @@ export interface UseTimeAgoOptions< * @default false */ controls?: Controls - /** - * Intervals to update, set 0 to disable auto update - * - * @deprecated Please use `scheduler` option instead - * @default 30_000 - */ - updateInterval?: number } export interface UseTimeAgoUnit< Unit extends string = UseTimeAgoUnitNamesDefault, diff --git a/plugins/vueuse/.agents/skills/vueuse-functions/references/useTimeAgoIntl.md b/plugins/vueuse/.agents/skills/vueuse-functions/references/useTimeAgoIntl.md index 9f9a65a0..955a04b0 100644 --- a/plugins/vueuse/.agents/skills/vueuse-functions/references/useTimeAgoIntl.md +++ b/plugins/vueuse/.agents/skills/vueuse-functions/references/useTimeAgoIntl.md @@ -71,13 +71,6 @@ export interface UseTimeAgoIntlOptions * @default false */ controls?: Controls - /** - * Update interval in milliseconds, set 0 to disable auto update - * - * @deprecated Please use `scheduler` option instead - * @default 30_000 - */ - updateInterval?: number } type UseTimeAgoReturn = Controls extends true ? { diff --git a/plugins/vueuse/.agents/skills/vueuse-functions/references/useTimestamp.md b/plugins/vueuse/.agents/skills/vueuse-functions/references/useTimestamp.md index 37b1d693..f1c2d927 100644 --- a/plugins/vueuse/.agents/skills/vueuse-functions/references/useTimestamp.md +++ b/plugins/vueuse/.agents/skills/vueuse-functions/references/useTimestamp.md @@ -54,20 +54,6 @@ export interface UseTimestampOptions< * @default 0 */ offset?: number - /** - * Update the timestamp immediately - * - * @deprecated Please use `scheduler` option instead - * @default true - */ - immediate?: boolean - /** - * Update interval, or use requestAnimationFrame - * - * @deprecated Please use `scheduler` option instead - * @default requestAnimationFrame - */ - interval?: "requestAnimationFrame" | number /** * Callback on each update */ diff --git a/plugins/vueuse/.agents/skills/vueuse-functions/references/useVibrate.md b/plugins/vueuse/.agents/skills/vueuse-functions/references/useVibrate.md index 004a45f5..137a978a 100644 --- a/plugins/vueuse/.agents/skills/vueuse-functions/references/useVibrate.md +++ b/plugins/vueuse/.agents/skills/vueuse-functions/references/useVibrate.md @@ -54,16 +54,6 @@ export interface UseVibrateOptions * */ pattern?: MaybeRefOrGetter> - /** - * Interval to run a persistent vibration, in ms - * - * Pass `0` to disable - * - * @deprecated Please use `scheduler` option instead - * @default 0 - * - */ - interval?: number } export interface UseVibrateReturn extends Supportable { pattern: MaybeRefOrGetter> diff --git a/plugins/vueuse/.agents/skills/vueuse-functions/references/useWebMCP.md b/plugins/vueuse/.agents/skills/vueuse-functions/references/useWebMCP.md new file mode 100644 index 00000000..e4e81547 --- /dev/null +++ b/plugins/vueuse/.agents/skills/vueuse-functions/references/useWebMCP.md @@ -0,0 +1,245 @@ +--- +category: Browser +--- + +# useWebMCP + +Register a [WebMCP](https://github.com/webmachinelearning/webmcp) tool and tie its lifecycle to the current Vue scope. + +WebMCP lets a page expose JavaScript functions as "tools" that an AI agent (browser-built-in, iframe-hosted, or extension) can discover and call, instead of scraping the DOM, the accessibility tree, or screenshots. `useWebMCP` wraps the imperative, `AbortSignal`-based registration API in a declarative composable: the tool is registered when the composable runs and **unregistered automatically when the scope is disposed**, so the set of tools an agent sees stays in lockstep with what is actually on screen. + +::: warning Experimental +The WebMCP spec is `🧪` experimental and exposes the imperative API on `document.modelContext` (`registerTool` + an `AbortSignal` for unregistration). This composable feature-detects and degrades to a no-op everywhere the API is absent — check `isSupported` before relying on it. +::: + +## Usage + +```ts +import { useWebMCP } from '@vueuse/core' +import { shallowRef } from 'vue' + +const todos = shallowRef([]) + +const { isSupported, isRegistered, error } = useWebMCP({ + name: 'add-todo', + description: 'Add a new item to the user\'s active todo list', + inputSchema: { + type: 'object', + properties: { + text: { type: 'string', description: 'The text content of the todo item' }, + }, + required: ['text'], + }, + async execute({ text }) { + todos.value = [...todos.value, text] + return `Added todo item: "${text}" successfully.` + }, +}) +``` + +The raw imperative API this wraps looks like: + +```ts +const controller = new AbortController() + +document.modelContext.registerTool({ + name: 'add-todo', + description: 'Add a new item to the user\'s active todo list', + inputSchema: { /* … */ }, + async execute({ text }) { + return { content: [{ type: 'text', text: `Added todo item: "${text}".` }] } + }, +}, { signal: controller.signal }) + +// Unregister later: +controller.abort() +``` + +## Result normalization + +Whatever `execute` returns is normalized into a valid MCP tool result: + +- a **string** → `{ content: [{ type: 'text', text }] }` +- **`undefined`/`null`** (no return) → `{ content: [] }` (success, no payload) +- a value that is **already** `{ content: [...] }` → passed through untouched +- a **thrown value** — `Error` or not (`throw 'not signed in'`, `throw { code: 403 }`) → `{ content: [{ type: 'text', text }], isError: true }`, after `onError`. A failure must never read as success to the agent. +- a **returned `Error`** → treated exactly like a throw: `onError` fires, then an `isError` result +- anything else (object/array/number) → JSON-serialized into a text block + +## Reactive & conditional registration + +`name`, `description`, `inputSchema`, `annotations` and `enabled` accept refs or getters. Changing a discoverable field re-registers the tool; toggling `enabled` unregisters and re-registers it. `execute`, `formatOutput` and `onError` are read live at call time, so a changing closure never churns the registration. + +```ts +import { useWebMCP } from '@vueuse/core' +import { shallowRef } from 'vue' + +const signedIn = shallowRef(false) + +useWebMCP({ + name: 'checkout', + description: 'Complete the checkout for the current cart', + enabled: signedIn, // only exposed to agents while signed in + annotations: { readOnlyHint: false }, + execute() { + // … + }, + onError(err) { + console.error('checkout tool failed', err) + }, +}) +``` + +## Registering multiple tools + +Call `useWebMCP` once per tool to register several — each call manages its own registration lifecycle. + +```ts +import { useWebMCP } from '@vueuse/core' + +useWebMCP({ + name: 'add-todo', + description: 'Add a new item to the todo list', + execute({ text }) { + // … + }, +}) + +useWebMCP({ + name: 'clear-todos', + description: 'Remove every item from the todo list', + annotations: { readOnlyHint: false }, + execute() { + // … + }, +}) +``` + +## References + +- [WebMCP explainer & spec (webmachinelearning/webmcp)](https://github.com/webmachinelearning/webmcp) +- [GoogleChromeLabs/use-webmcp-tool](https://github.com/GoogleChromeLabs/use-webmcp-tool) — the React hook this composable is modeled after + +## Type Declarations + +```ts +/** + * A single block of a WebMCP tool result. + * + * @see https://github.com/webmachinelearning/webmcp + */ +export interface WebMCPToolContent { + type: string + text?: string + [key: string]: unknown +} +/** + * The normalized result an agent receives after a tool runs. + */ +export interface WebMCPToolResponse { + content: WebMCPToolContent[] + isError?: boolean +} +/** + * Hints an author can attach to a tool to shape how an agent uses it. + */ +export interface WebMCPToolAnnotations { + /** + * The tool does not mutate state and is safe to call speculatively. + */ + readOnlyHint?: boolean + /** + * The tool may return content that should be treated as untrusted. + */ + untrustedContentHint?: boolean + [key: string]: unknown +} +/** + * The imperative descriptor passed to `document.modelContext.registerTool`. + */ +export interface WebMCPToolDescriptor { + name: string + description: string + inputSchema?: object + annotations?: WebMCPToolAnnotations + execute: (args: any) => Promise | WebMCPToolResponse +} +/** + * The (experimental) imperative WebMCP API surface exposed on `document`. + */ +export interface ModelContext { + registerTool: ( + tool: WebMCPToolDescriptor, + options?: { + signal?: AbortSignal + }, + ) => void +} +export interface UseWebMCPOptions extends ConfigurableDocument { + /** + * Tool identifier the agent uses to invoke this tool. + */ + name: MaybeRefOrGetter + /** + * Natural-language description the agent reads to decide when to call it. + */ + description: MaybeRefOrGetter + /** + * JSON Schema describing the tool arguments. + */ + inputSchema?: MaybeRefOrGetter + /** + * Hints (`readOnlyHint`, `untrustedContentHint`, …) shaping agent behavior. + */ + annotations?: MaybeRefOrGetter + /** + * The function the agent calls. May be async. Its return value is normalized + * into a WebMCP tool result, and any thrown/returned `Error` becomes an + * `isError` result. + */ + execute: (args: Args) => Result | Promise + /** + * Register the tool only while this is `true`. + * + * @default true + */ + enabled?: MaybeRefOrGetter + /** + * Shape the `execute` result before it is normalized into a tool response. + */ + formatOutput?: (result: Result, args: Args) => unknown + /** + * Side effect invoked when `execute` (or `formatOutput`) throws/returns an error. + */ + onError?: (error: unknown) => void +} +export interface UseWebMCPReturn extends Supportable { + /** + * Whether the tool is currently registered with the browser. + */ + isRegistered: ShallowRef + /** + * Registration error, e.g. a `NotAllowedError` from a `tools` permissions policy. + */ + error: ShallowRef +} +/** + * Register a [WebMCP](https://github.com/webmachinelearning/webmcp) tool and + * tie its lifecycle to the current scope. + * + * The tool is registered when the composable runs (and whenever a discoverable + * part — `name`, `description`, `inputSchema`, `annotations` or `enabled` — + * changes) and unregistered automatically on scope dispose, so the tools an + * agent sees stay in lockstep with what is on screen. Call it multiple times to + * register multiple tools. + * + * The API is experimental (`document.modelContext`), so this feature-detects + * and degrades to a no-op wherever it is absent. + * + * @see https://vueuse.org/useWebMCP + * @see https://github.com/webmachinelearning/webmcp + */ +export declare function useWebMCP, Result = unknown>( + options: UseWebMCPOptions, +): UseWebMCPReturn +``` diff --git a/plugins/vueuse/.agents/skills/vueuse-functions/references/useWebSocket.md b/plugins/vueuse/.agents/skills/vueuse-functions/references/useWebSocket.md index 1344eedc..960d9157 100644 --- a/plugins/vueuse/.agents/skills/vueuse-functions/references/useWebSocket.md +++ b/plugins/vueuse/.agents/skills/vueuse-functions/references/useWebSocket.md @@ -186,13 +186,6 @@ export interface UseWebSocketOptions { * Response message for the heartbeat, if undefined the message will be used */ responseMessage?: MaybeRefOrGetter - /** - * Interval, in milliseconds - * - * @deprecated Please use `scheduler` option instead - * @default 1000 - */ - interval?: number /** * Heartbeat response timeout, in milliseconds * diff --git a/plugins/vueuse/.agents/skills/vueuse-functions/references/watchIgnorable.md b/plugins/vueuse/.agents/skills/vueuse-functions/references/watchIgnorable.md index 786532b2..ac5d6df4 100644 --- a/plugins/vueuse/.agents/skills/vueuse-functions/references/watchIgnorable.md +++ b/plugins/vueuse/.agents/skills/vueuse-functions/references/watchIgnorable.md @@ -79,7 +79,7 @@ await nextTick() // logs: Changed to after! ## Recommended Readings -- [Ignorable Watch](https://patak.dev/vue/ignorable-watch.html) - by [@patak-dev](https://github.com/patak-dev) +- [Ignorable Watch](https://patak.dev/vue/ignorable-watch.html) - by [@patak-cat](https://github.com/patak-cat) ## Type Declarations diff --git a/plugins/vueuse/agent/skills/vueuse-functions/SKILL.md b/plugins/vueuse/agent/skills/vueuse-functions/SKILL.md index 5d90b410..abaa9705 100644 --- a/plugins/vueuse/agent/skills/vueuse-functions/SKILL.md +++ b/plugins/vueuse/agent/skills/vueuse-functions/SKILL.md @@ -93,6 +93,7 @@ IMPORTANT: Each function entry includes a short `Description` and a detailed `Re | [`useFullscreen`](references/useFullscreen.md) | Reactive [Fullscreen API](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API) | AUTO | | [`useGamepad`](references/useGamepad.md) | Provides reactive bindings for the [Gamepad API](https://developer.mozilla.org/en-US/docs/Web/API/Gamepad_API) | AUTO | | [`useImage`](references/useImage.md) | Reactive load an image in the browser | AUTO | +| [`useLiveAnnouncer`](references/useLiveAnnouncer.md) | Accessible way to announce messages to screen reader users (ARIA live regions) | AUTO | | [`useMediaControls`](references/useMediaControls.md) | Reactive media controls for both `audio` and `video` elements | AUTO | | [`useMediaQuery`](references/useMediaQuery.md) | Reactive [Media Query](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Testing_media_queries) | AUTO | | [`useMemory`](references/useMemory.md) | Reactive Memory Info | AUTO | @@ -117,6 +118,7 @@ IMPORTANT: Each function entry includes a short `Description` and a detailed `Re | [`useUrlSearchParams`](references/useUrlSearchParams.md) | Reactive [URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) | AUTO | | [`useVibrate`](references/useVibrate.md) | Reactive [Vibration API](https://developer.mozilla.org/en-US/docs/Web/API/Vibration_API) | AUTO | | [`useWakeLock`](references/useWakeLock.md) | Reactive [Screen Wake Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Screen_Wake_Lock_API) | AUTO | +| [`useWebMCP`](references/useWebMCP.md) | Register a [WebMCP](https://github.com/webmachinelearning/webmcp) tool and tie its lifecycle to the current Vue scope | AUTO | | [`useWebNotification`](references/useWebNotification.md) | Reactive [Notification](https://developer.mozilla.org/en-US/docs/Web/API/notification) | AUTO | | [`useWebWorker`](references/useWebWorker.md) | Simple [Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) registration and communication | AUTO | | [`useWebWorkerFn`](references/useWebWorkerFn.md) | Run expensive functions without blocking the UI | AUTO | @@ -193,7 +195,6 @@ IMPORTANT: Each function entry includes a short `Description` and a detailed `Re | [`computedInject`](references/computedInject.md) | Combine `computed` and `inject` | AUTO | | [`createReusableTemplate`](references/createReusableTemplate.md) | Define and reuse template inside the component scope | AUTO | | [`createTemplatePromise`](references/createTemplatePromise.md) | Template as Promise | AUTO | -| [`templateRef`](references/templateRef.md) | Shorthand for binding ref to template element | AUTO | | [`tryOnBeforeMount`](references/tryOnBeforeMount.md) | Safe `onBeforeMount` | AUTO | | [`tryOnBeforeUnmount`](references/tryOnBeforeUnmount.md) | Safe `onBeforeUnmount` | AUTO | | [`tryOnMounted`](references/tryOnMounted.md) | Safe `onMounted` | AUTO | @@ -275,6 +276,7 @@ IMPORTANT: Each function entry includes a short `Description` and a detailed `Re |----------|-------------|------------| | [`useCountdown`](references/useCountdown.md) | Reactive countdown timer in seconds | AUTO | | [`useDateFormat`](references/useDateFormat.md) | Get the formatted date according to the string of tokens passed in | AUTO | +| [`useTemporalNow`](references/useTemporalNow.md) | Reactive [Temporal API](https://tc39.es/proposal-temporal/docs/) with timezone conversion and calendar system support | AUTO | | [`useTimeAgo`](references/useTimeAgo.md) | Reactive time ago | AUTO | | [`useTimeAgoIntl`](references/useTimeAgoIntl.md) | Reactive time ago with i18n supported | AUTO | diff --git a/plugins/vueuse/agent/skills/vueuse-functions/references/injectLocal.md b/plugins/vueuse/agent/skills/vueuse-functions/references/injectLocal.md index 165acb30..3ac2f1a0 100644 --- a/plugins/vueuse/agent/skills/vueuse-functions/references/injectLocal.md +++ b/plugins/vueuse/agent/skills/vueuse-functions/references/injectLocal.md @@ -29,7 +29,7 @@ const injectedValue = injectLocal('MyInjectionKey') // injectedValue === 1 * const injectedValue = injectLocal('MyInjectionKey') // injectedValue === 1 * ``` * - * @__NO_SIDE_EFFECTS__ + * @NO_SIDE_EFFECTS */ export declare const injectLocal: typeof inject ``` diff --git a/plugins/vueuse/agent/skills/vueuse-functions/references/useBreakpoints.md b/plugins/vueuse/agent/skills/vueuse-functions/references/useBreakpoints.md index 13caff9d..df8b21b4 100644 --- a/plugins/vueuse/agent/skills/vueuse-functions/references/useBreakpoints.md +++ b/plugins/vueuse/agent/skills/vueuse-functions/references/useBreakpoints.md @@ -90,7 +90,7 @@ const breakpoints = useBreakpoints(breakpointsTailwind, { #### Server Side Rendering and Nuxt -If you are using `useBreakpoints` with SSR enabled, then you need to specify which screen size you would like to render on the server and before hydration to avoid an hydration mismatch +If you are using `useBreakpoints` with SSR enabled, then you need to specify which screen size you would like to render on the server and before hydration to avoid a hydration mismatch ```ts import { breakpointsTailwind, useBreakpoints } from '@vueuse/core' diff --git a/plugins/vueuse/agent/skills/vueuse-functions/references/useCloned.md b/plugins/vueuse/agent/skills/vueuse-functions/references/useCloned.md index f48c19e2..22ce00a5 100644 --- a/plugins/vueuse/agent/skills/vueuse-functions/references/useCloned.md +++ b/plugins/vueuse/agent/skills/vueuse-functions/references/useCloned.md @@ -97,6 +97,6 @@ export type CloneFn = (x: F) => T export declare function cloneFnJSON(source: T): T export declare function useCloned( source: MaybeRefOrGetter, - options?: UseClonedOptions, + options?: UseClonedOptions, ): UseClonedReturn ``` diff --git a/plugins/vueuse/agent/skills/vueuse-functions/references/useCountdown.md b/plugins/vueuse/agent/skills/vueuse-functions/references/useCountdown.md index ac6734b1..79cf396a 100644 --- a/plugins/vueuse/agent/skills/vueuse-functions/references/useCountdown.md +++ b/plugins/vueuse/agent/skills/vueuse-functions/references/useCountdown.md @@ -50,12 +50,6 @@ start() ```ts export interface UseCountdownOptions extends ConfigurableScheduler { - /** - * Interval for the countdown in milliseconds. Default is 1000ms. - * - * @deprecated Please use `scheduler` option instead - */ - interval?: MaybeRefOrGetter /** * Callback function called when the countdown reaches 0. */ @@ -64,13 +58,6 @@ export interface UseCountdownOptions extends ConfigurableScheduler { * Callback function called on each tick of the countdown. */ onTick?: () => void - /** - * Start the countdown immediately - * - * @deprecated Please use `scheduler` option instead - * @default false - */ - immediate?: boolean } export interface UseCountdownReturn extends Pausable { /** diff --git a/plugins/vueuse/agent/skills/vueuse-functions/references/useElementByPoint.md b/plugins/vueuse/agent/skills/vueuse-functions/references/useElementByPoint.md index 9c8326a9..9dc3032a 100644 --- a/plugins/vueuse/agent/skills/vueuse-functions/references/useElementByPoint.md +++ b/plugins/vueuse/agent/skills/vueuse-functions/references/useElementByPoint.md @@ -23,10 +23,6 @@ export interface UseElementByPointOptions x: MaybeRefOrGetter y: MaybeRefOrGetter multiple?: MaybeRefOrGetter - /** @deprecated Please use `scheduler` option instead */ - immediate?: boolean - /** @deprecated Please use `scheduler` option instead */ - interval?: "requestAnimationFrame" | number } export interface UseElementByPointReturn extends Supportable, Pausable { diff --git a/plugins/vueuse/agent/skills/vueuse-functions/references/useIDBKeyval.md b/plugins/vueuse/agent/skills/vueuse-functions/references/useIDBKeyval.md index d27595ae..5ed8c1e0 100644 --- a/plugins/vueuse/agent/skills/vueuse-functions/references/useIDBKeyval.md +++ b/plugins/vueuse/agent/skills/vueuse-functions/references/useIDBKeyval.md @@ -37,6 +37,15 @@ console.log('IDB transaction finished!') storedObject.value = null ``` +## Cross-tab syncing + +Changes are automatically synced across browser tabs using the [`BroadcastChannel` API](https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel). This is enabled by default and can be disabled via the `listenToStorageChanges` option. + +```ts +// disable cross-tab syncing +const { data } = useIDBKeyval('my-key', 'default', { listenToStorageChanges: false }) +``` + ## Type Declarations ```ts @@ -44,7 +53,8 @@ interface Serializer { read: (raw: unknown) => T write: (value: T) => unknown } -export interface UseIDBOptions extends ConfigurableFlush { +export interface UseIDBOptions + extends ConfigurableFlush, ConfigurableWindow { /** * Watch for deep changes * @@ -73,10 +83,18 @@ export interface UseIDBOptions extends ConfigurableFlush { * Custom data serialization */ serializer?: Serializer + /** + * Listen to storage changes from other tabs via BroadcastChannel, + * useful for multiple tabs applications + * + * @default true + */ + listenToStorageChanges?: boolean } export interface UseIDBKeyvalReturn { data: RemovableRef isFinished: ShallowRef + isSupported: ComputedRef set: (value: T) => Promise } /** diff --git a/plugins/vueuse/agent/skills/vueuse-functions/references/useIntersectionObserver.md b/plugins/vueuse/agent/skills/vueuse-functions/references/useIntersectionObserver.md index 23ca821e..71cc66b7 100644 --- a/plugins/vueuse/agent/skills/vueuse-functions/references/useIntersectionObserver.md +++ b/plugins/vueuse/agent/skills/vueuse-functions/references/useIntersectionObserver.md @@ -31,6 +31,34 @@ const { stop } = useIntersectionObserver( ``` +### Controls and cleanup + +`useIntersectionObserver` returns controls for the underlying observer: + +| State | Type | Description | +| ------------- | ---------------------- | ------------------------------------------------------------------------------------- | +| `isSupported` | `ComputedRef` | Whether the `IntersectionObserver` API is available. | +| `isActive` | `ShallowRef` | Whether the observer is currently running. Turns `false` after `pause()` or `stop()`. | +| `pause` | `() => void` | Pause observing and set `isActive` to `false`. | +| `resume` | `() => void` | Resume observing. | +| `stop` | `() => void` | Stop observing permanently. | + +The observer is disconnected automatically via [`tryOnScopeDispose`](https://vueuse.org/shared/tryOnScopeDispose/) when the component or effect scope that created it is disposed, so in most cases you don't need to call `stop` yourself. Call `stop()` to disconnect the observer earlier, for example once the element has become visible: + +```ts +import { useIntersectionObserver } from '@vueuse/core' +// ---cut--- +const { stop } = useIntersectionObserver( + target, + ([entry]) => { + if (entry?.isIntersecting) { + // react to the element becoming visible once, then stop observing + stop() + } + }, +) +``` + ## Directive Usage ```vue diff --git a/plugins/vueuse/agent/skills/vueuse-functions/references/useLiveAnnouncer.md b/plugins/vueuse/agent/skills/vueuse-functions/references/useLiveAnnouncer.md new file mode 100644 index 00000000..1124fe8a --- /dev/null +++ b/plugins/vueuse/agent/skills/vueuse-functions/references/useLiveAnnouncer.md @@ -0,0 +1,77 @@ +--- +category: Browser +--- + +# useLiveAnnouncer + +Accessible way to announce messages to screen reader users (ARIA live regions). + +## Usage + +```ts +import { useLiveAnnouncer } from '@vueuse/core' + +const { announce, polite, assertive } = useLiveAnnouncer() + +announce('This is a polite announcement') +polite('This is also a polite announcement') +assertive('Important message!') +``` + +The message stays in the live region until it is replaced by the next announcement. Pass a `timeout` (in milliseconds) to automatically clear it after a delay: + +```ts +// clears the message after 3000ms +announce('Saved successfully', 'polite', 3000) +polite('Saved successfully', 3000) +assertive('Network error', 3000) +``` + +## Accessibility + +The announcer uses the following ARIA attributes: + +- **Polite**: `role="status"`, `aria-live="polite"`, `aria-atomic="true"` +- **Assertive**: `role="alert"`, `aria-live="assertive"`, `aria-atomic="true"` + +These ensure robust support across different screen readers. + +## Options + +### idPrefix + +- Type: `string` +- Default: `'vueuse-live-announcer'` + +Prefix for the id of the announcer elements. The generated elements will have IDs `${idPrefix}-container`, `${idPrefix}-polite`, and `${idPrefix}-assertive`. + +### window + +- Type: `Window` +- Default: `defaultWindow` + +The window object where the announcer elements will be created. + +## Type Declarations + +```ts +export interface UseLiveAnnouncerOptions extends ConfigurableWindow { + /** + * The prefix for the id of the announcer elements. + * @default 'vueuse-live-announcer' + */ + idPrefix?: string +} +export interface UseLiveAnnouncerReturn { + announce: ( + message: string, + mode?: "polite" | "assertive", + timeout?: number, + ) => void + polite: (message: string, timeout?: number) => void + assertive: (message: string, timeout?: number) => void +} +export declare function useLiveAnnouncer( + options?: UseLiveAnnouncerOptions, +): UseLiveAnnouncerReturn +``` diff --git a/plugins/vueuse/agent/skills/vueuse-functions/references/useMediaQuery.md b/plugins/vueuse/agent/skills/vueuse-functions/references/useMediaQuery.md index fd6a4445..0a5b9c74 100644 --- a/plugins/vueuse/agent/skills/vueuse-functions/references/useMediaQuery.md +++ b/plugins/vueuse/agent/skills/vueuse-functions/references/useMediaQuery.md @@ -17,7 +17,7 @@ const isPreferredDark = useMediaQuery('(prefers-color-scheme: dark)') #### Server Side Rendering and Nuxt -If you are using `useMediaQuery` with SSR enabled, then you need to specify which screen size you would like to render on the server and before hydration to avoid an hydration mismatch +If you are using `useMediaQuery` with SSR enabled, then you need to specify which screen size you would like to render on the server and before hydration to avoid a hydration mismatch ```ts import { useMediaQuery } from '@vueuse/core' diff --git a/plugins/vueuse/agent/skills/vueuse-functions/references/useMemory.md b/plugins/vueuse/agent/skills/vueuse-functions/references/useMemory.md index 25c09296..48ee5758 100644 --- a/plugins/vueuse/agent/skills/vueuse-functions/references/useMemory.md +++ b/plugins/vueuse/agent/skills/vueuse-functions/references/useMemory.md @@ -37,24 +37,7 @@ export interface MemoryInfo { readonly usedJSHeapSize: number [Symbol.toStringTag]: "MemoryInfo" } -export interface UseMemoryOptions extends ConfigurableScheduler { - /** - * Start the timer immediately - * - * @deprecated Please use `scheduler` option instead - * @default true - */ - immediate?: boolean - /** - * Execute the callback immediately after calling `resume` - * - * @deprecated Please use `scheduler` option instead - * @default false - */ - immediateCallback?: boolean - /** @deprecated Please use `scheduler` option instead */ - interval?: number -} +export interface UseMemoryOptions extends ConfigurableScheduler {} export interface UseMemoryReturn extends Supportable { memory: ShallowRef } diff --git a/plugins/vueuse/agent/skills/vueuse-functions/references/useNow.md b/plugins/vueuse/agent/skills/vueuse-functions/references/useNow.md index fcc1252c..9e029367 100644 --- a/plugins/vueuse/agent/skills/vueuse-functions/references/useNow.md +++ b/plugins/vueuse/agent/skills/vueuse-functions/references/useNow.md @@ -48,20 +48,6 @@ export interface UseNowOptions< * @default false */ controls?: Controls - /** - * Start the clock immediately - * - * @deprecated Please use `scheduler` option instead - * @default true - */ - immediate?: boolean - /** - * Update interval in milliseconds, or use requestAnimationFrame - * - * @deprecated Please use `scheduler` option instead - * @default requestAnimationFrame - */ - interval?: "requestAnimationFrame" | number } export type UseNowReturn = Controls extends true ? { diff --git a/plugins/vueuse/agent/skills/vueuse-functions/references/usePerformanceObserver.md b/plugins/vueuse/agent/skills/vueuse-functions/references/usePerformanceObserver.md index d874c9d8..18b31dfd 100644 --- a/plugins/vueuse/agent/skills/vueuse-functions/references/usePerformanceObserver.md +++ b/plugins/vueuse/agent/skills/vueuse-functions/references/usePerformanceObserver.md @@ -11,11 +11,11 @@ Observe performance metrics. ```ts import { usePerformanceObserver } from '@vueuse/core' -const entrys = ref([]) +const entries = ref([]) usePerformanceObserver({ entryTypes: ['paint'], }, (list) => { - entrys.value = list.getEntries() + entries.value = list.getEntries() }) ``` diff --git a/plugins/vueuse/agent/skills/vueuse-functions/references/useRefHistory.md b/plugins/vueuse/agent/skills/vueuse-functions/references/useRefHistory.md index f47d9fec..57f9eae0 100644 --- a/plugins/vueuse/agent/skills/vueuse-functions/references/useRefHistory.md +++ b/plugins/vueuse/agent/skills/vueuse-functions/references/useRefHistory.md @@ -200,7 +200,7 @@ Another option is to avoid mutating the original ref value using `arr.value = [. ## Recommended Readings -- [History and Persistence](https://patak.dev/vue/history-and-persistence.html) - by [@patak-dev](https://github.com/patak-dev) +- [History and Persistence](https://patak.dev/vue/history-and-persistence.html) - by [@patak-cat](https://github.com/patak-cat) ## Type Declarations diff --git a/plugins/vueuse/agent/skills/vueuse-functions/references/useStepper.md b/plugins/vueuse/agent/skills/vueuse-functions/references/useStepper.md index e4c20fdd..04ff113d 100644 --- a/plugins/vueuse/agent/skills/vueuse-functions/references/useStepper.md +++ b/plugins/vueuse/agent/skills/vueuse-functions/references/useStepper.md @@ -126,6 +126,13 @@ export interface UseStepperReturn { /** Checks if the current step is after the given step. */ isAfter: (step: StepName) => boolean } +/** + * Provides helpers for building a multi-step wizard interface. + * + * @see https://vueuse.org/useStepper + * + * @__NO_SIDE_EFFECTS__ + */ export declare function useStepper( steps: MaybeRef, initialStep?: T, diff --git a/plugins/vueuse/agent/skills/vueuse-functions/references/useTemporalNow.md b/plugins/vueuse/agent/skills/vueuse-functions/references/useTemporalNow.md new file mode 100644 index 00000000..73d80e64 --- /dev/null +++ b/plugins/vueuse/agent/skills/vueuse-functions/references/useTemporalNow.md @@ -0,0 +1,321 @@ +--- +category: Time +--- + +# useTemporalNow + +Reactive [Temporal API](https://tc39.es/proposal-temporal/docs/) with timezone conversion and calendar system support. + +Uses the modern Temporal API instead of the legacy `Date` object, providing better timezone handling, calendar systems, and date/time operations. + +## Requirements + +This function relies on the [`Temporal`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal) API. It does **not** bundle or depend on any Temporal implementation — by default it reads the global `Temporal` object, but you can also pass your own implementation via the `temporal` option. + +- Modern JS engines (recent Node.js, Deno, and browsers) already expose `Temporal` natively, or will soon. +- For environments without native support, install a polyfill yourself, for example [`temporal-polyfill`](https://github.com/fullcalendar/temporal-polyfill): + + ```bash + npm i temporal-polyfill + ``` + + and either load it once as a global, before this function is used (e.g. in your app's entry point): + + ```ts + import 'temporal-polyfill/global' + ``` + + If you need calendar systems beyond `iso8601`/`gregory` (e.g. `islamic`, `hebrew`, `chinese`, `japanese` as used in the examples below), use the `/full/` entry point instead: + + ```ts + import 'temporal-polyfill/full/global' + ``` + + ...or pass it explicitly via the `temporal` option instead of touching the global scope: + + ```ts + import { useTemporalNow } from '@vueuse/core' + import { Temporal } from 'temporal-polyfill' + + const temporal = useTemporalNow({ temporal: Temporal }) + ``` + + [`@js-temporal/polyfill`](https://github.com/js-temporal/temporal-polyfill) is another common alternative. It does not install a global `Temporal` object by itself, so the `temporal` option is the natural way to use it. Its type declarations are authored independently from TypeScript's own ambient `Temporal` types (unlike `temporal-polyfill`, which derives its types from the same source), so a cast is needed to satisfy the `temporal` option at compile time — the runtime objects are spec-compliant and interoperate fine: + + ```ts + import { Temporal } from '@js-temporal/polyfill' + import { useTemporalNow } from '@vueuse/core' + + const temporal = useTemporalNow({ temporal: Temporal as unknown as typeof globalThis.Temporal }) + ``` + +If no `Temporal` implementation can be found (neither passed via the `temporal` option nor available globally), calling `useTemporalNow` will throw an error. + +## Usage + +### Basic Usage + +```vue + + + +``` + +### Timezone Conversion + +```ts +import { useTemporalNow } from '@vueuse/core' + +const temporal = useTemporalNow({ timezone: 'America/New_York' }) + +// Convert to different timezones +const tokyoTime = temporal.toTimezone('Asia/Tokyo') +const londonTime = temporal.toTimezone('Europe/London') +const utcTime = temporal.toTimezone('UTC') + +// Change timezone reactively +temporal.timezone.value = 'Europe/Berlin' +``` + +### Calendar Systems + +```ts +import { useTemporalNow } from '@vueuse/core' + +const temporal = useTemporalNow({ calendar: 'gregory' }) + +// Convert to different calendar systems +const islamicDate = temporal.toCalendar('islamic-umalqura') +const hebrewDate = temporal.toCalendar('hebrew') +const chineseDate = temporal.toCalendar('chinese') + +// Change calendar reactively +temporal.calendar.value = 'islamic-umalqura' +``` + +### Date/Time Manipulation + +```ts +import { useTemporalNow } from '@vueuse/core' + +const { now, add, subtract, compare } = useTemporalNow() + +// Add/subtract durations +const nextWeek = add('P7D') // Add 7 days +const lastMonth = subtract('P1M') // Subtract 1 month +const inTwoHours = add('PT2H') // Add 2 hours + +// Compare dates +const futureDate = add('P1Y') // Add 1 year +const comparison = compare(futureDate) // -1 (now is before futureDate) +``` + +### Format Options + +```ts +import { useTemporalNow } from '@vueuse/core' + +const { format } = useTemporalNow() + +// Different formatting options +const short = format({ dateStyle: 'short' }) // "12/25/23" +const long = format({ dateStyle: 'long' }) // "December 25, 2023" +const time = format({ timeStyle: 'medium' }) // "3:30:00 PM" +const custom = format({ + weekday: 'long', + year: 'numeric', + month: 'long', + day: 'numeric' +}) // "Monday, December 25, 2023" +``` + +### Control Auto-Update + +By default `useTemporalNow` updates on every `requestAnimationFrame`. Pass a +custom `scheduler` to control how updates are driven — for example, tick on a +fixed interval, or start paused: + +```ts +import { useTemporalNow } from '@vueuse/core' +import { useIntervalFn } from '@vueuse/shared' + +const { pause, resume, isActive } = useTemporalNow({ + // Update every 500ms instead of on every animation frame, + // and don't start immediately. + scheduler: cb => useIntervalFn(cb, 500, { immediate: false }), +}) + +// Manually control updates +resume() // Start auto-update +pause() // Stop auto-update + +console.log(isActive.value) // true/false +``` + +## Examples + +### World Clock + +```vue + + + +``` + +### Calendar System Converter + +```vue + + + +``` + +## Type Declarations + +```ts +export interface UseTemporalNowOptions extends ConfigurableScheduler { + /** + * Initial timezone + * + * @default 'UTC' + */ + timezone?: string + /** + * Calendar system to use + * + * @default 'gregory' + */ + calendar?: string + /** + * Custom `Temporal` implementation to use, e.g. the `Temporal` export from + * `@js-temporal/polyfill` or another polyfill, instead of relying on the + * global `Temporal` object. + * + * @default globalThis.Temporal + */ + temporal?: typeof Temporal +} +export interface UseTemporalNowReturn extends Pausable { + /** + * Current `Temporal.ZonedDateTime` + */ + now: Ref + /** + * Current timezone + */ + timezone: Ref + /** + * Current calendar + */ + calendar: Ref + /** + * Convert to a different timezone + */ + toTimezone: (timezone: string) => Temporal.ZonedDateTime + /** + * Convert to a different calendar + */ + toCalendar: (calendar: string) => Temporal.ZonedDateTime + /** + * Get the `Temporal.PlainDate` (date only) + */ + toPlainDate: () => Temporal.PlainDate + /** + * Get the `Temporal.PlainTime` (time only) + */ + toPlainTime: () => Temporal.PlainTime + /** + * Get the `Temporal.PlainDateTime` (local date/time) + */ + toPlainDateTime: () => Temporal.PlainDateTime + /** + * Format the current date/time + */ + format: (options?: Intl.DateTimeFormatOptions) => string + /** + * Add a duration + */ + add: (duration: Temporal.DurationLike) => Temporal.ZonedDateTime + /** + * Subtract a duration + */ + subtract: (duration: Temporal.DurationLike) => Temporal.ZonedDateTime + /** + * Compare with another date/time + */ + compare: (other: Temporal.ZonedDateTime | string) => number +} +/** + * Reactive Temporal API with timezone and calendar support. + * + * @see https://vueuse.org/useTemporalNow + * @param options - Configuration options + */ +export declare function useTemporalNow( + options?: UseTemporalNowOptions, +): UseTemporalNowReturn +``` diff --git a/plugins/vueuse/agent/skills/vueuse-functions/references/useThrottleFn.md b/plugins/vueuse/agent/skills/vueuse-functions/references/useThrottleFn.md index 85e22bb0..bc20ae50 100644 --- a/plugins/vueuse/agent/skills/vueuse-functions/references/useThrottleFn.md +++ b/plugins/vueuse/agent/skills/vueuse-functions/references/useThrottleFn.md @@ -37,7 +37,7 @@ useEventListener(window, 'resize', throttledFn) * @param ms A zero-or-greater delay in milliseconds. For event callbacks, values around 100 or 250 (or even higher) are most useful. * (default value: 200) * - * @param [trailing] if true, call fn again after the time is up (default value: false) + * @param [trailing] if true, call fn again after the time is up (default value: true) * * @param [leading] if true, call fn on the leading edge of the ms timeout (default value: true) * diff --git a/plugins/vueuse/agent/skills/vueuse-functions/references/useTimeAgo.md b/plugins/vueuse/agent/skills/vueuse-functions/references/useTimeAgo.md index 049d60a0..b779bb21 100644 --- a/plugins/vueuse/agent/skills/vueuse-functions/references/useTimeAgo.md +++ b/plugins/vueuse/agent/skills/vueuse-functions/references/useTimeAgo.md @@ -99,13 +99,6 @@ export interface UseTimeAgoOptions< * @default false */ controls?: Controls - /** - * Intervals to update, set 0 to disable auto update - * - * @deprecated Please use `scheduler` option instead - * @default 30_000 - */ - updateInterval?: number } export interface UseTimeAgoUnit< Unit extends string = UseTimeAgoUnitNamesDefault, diff --git a/plugins/vueuse/agent/skills/vueuse-functions/references/useTimeAgoIntl.md b/plugins/vueuse/agent/skills/vueuse-functions/references/useTimeAgoIntl.md index 9f9a65a0..955a04b0 100644 --- a/plugins/vueuse/agent/skills/vueuse-functions/references/useTimeAgoIntl.md +++ b/plugins/vueuse/agent/skills/vueuse-functions/references/useTimeAgoIntl.md @@ -71,13 +71,6 @@ export interface UseTimeAgoIntlOptions * @default false */ controls?: Controls - /** - * Update interval in milliseconds, set 0 to disable auto update - * - * @deprecated Please use `scheduler` option instead - * @default 30_000 - */ - updateInterval?: number } type UseTimeAgoReturn = Controls extends true ? { diff --git a/plugins/vueuse/agent/skills/vueuse-functions/references/useTimestamp.md b/plugins/vueuse/agent/skills/vueuse-functions/references/useTimestamp.md index 37b1d693..f1c2d927 100644 --- a/plugins/vueuse/agent/skills/vueuse-functions/references/useTimestamp.md +++ b/plugins/vueuse/agent/skills/vueuse-functions/references/useTimestamp.md @@ -54,20 +54,6 @@ export interface UseTimestampOptions< * @default 0 */ offset?: number - /** - * Update the timestamp immediately - * - * @deprecated Please use `scheduler` option instead - * @default true - */ - immediate?: boolean - /** - * Update interval, or use requestAnimationFrame - * - * @deprecated Please use `scheduler` option instead - * @default requestAnimationFrame - */ - interval?: "requestAnimationFrame" | number /** * Callback on each update */ diff --git a/plugins/vueuse/agent/skills/vueuse-functions/references/useVibrate.md b/plugins/vueuse/agent/skills/vueuse-functions/references/useVibrate.md index 004a45f5..137a978a 100644 --- a/plugins/vueuse/agent/skills/vueuse-functions/references/useVibrate.md +++ b/plugins/vueuse/agent/skills/vueuse-functions/references/useVibrate.md @@ -54,16 +54,6 @@ export interface UseVibrateOptions * */ pattern?: MaybeRefOrGetter> - /** - * Interval to run a persistent vibration, in ms - * - * Pass `0` to disable - * - * @deprecated Please use `scheduler` option instead - * @default 0 - * - */ - interval?: number } export interface UseVibrateReturn extends Supportable { pattern: MaybeRefOrGetter> diff --git a/plugins/vueuse/agent/skills/vueuse-functions/references/useWebMCP.md b/plugins/vueuse/agent/skills/vueuse-functions/references/useWebMCP.md new file mode 100644 index 00000000..e4e81547 --- /dev/null +++ b/plugins/vueuse/agent/skills/vueuse-functions/references/useWebMCP.md @@ -0,0 +1,245 @@ +--- +category: Browser +--- + +# useWebMCP + +Register a [WebMCP](https://github.com/webmachinelearning/webmcp) tool and tie its lifecycle to the current Vue scope. + +WebMCP lets a page expose JavaScript functions as "tools" that an AI agent (browser-built-in, iframe-hosted, or extension) can discover and call, instead of scraping the DOM, the accessibility tree, or screenshots. `useWebMCP` wraps the imperative, `AbortSignal`-based registration API in a declarative composable: the tool is registered when the composable runs and **unregistered automatically when the scope is disposed**, so the set of tools an agent sees stays in lockstep with what is actually on screen. + +::: warning Experimental +The WebMCP spec is `🧪` experimental and exposes the imperative API on `document.modelContext` (`registerTool` + an `AbortSignal` for unregistration). This composable feature-detects and degrades to a no-op everywhere the API is absent — check `isSupported` before relying on it. +::: + +## Usage + +```ts +import { useWebMCP } from '@vueuse/core' +import { shallowRef } from 'vue' + +const todos = shallowRef([]) + +const { isSupported, isRegistered, error } = useWebMCP({ + name: 'add-todo', + description: 'Add a new item to the user\'s active todo list', + inputSchema: { + type: 'object', + properties: { + text: { type: 'string', description: 'The text content of the todo item' }, + }, + required: ['text'], + }, + async execute({ text }) { + todos.value = [...todos.value, text] + return `Added todo item: "${text}" successfully.` + }, +}) +``` + +The raw imperative API this wraps looks like: + +```ts +const controller = new AbortController() + +document.modelContext.registerTool({ + name: 'add-todo', + description: 'Add a new item to the user\'s active todo list', + inputSchema: { /* … */ }, + async execute({ text }) { + return { content: [{ type: 'text', text: `Added todo item: "${text}".` }] } + }, +}, { signal: controller.signal }) + +// Unregister later: +controller.abort() +``` + +## Result normalization + +Whatever `execute` returns is normalized into a valid MCP tool result: + +- a **string** → `{ content: [{ type: 'text', text }] }` +- **`undefined`/`null`** (no return) → `{ content: [] }` (success, no payload) +- a value that is **already** `{ content: [...] }` → passed through untouched +- a **thrown value** — `Error` or not (`throw 'not signed in'`, `throw { code: 403 }`) → `{ content: [{ type: 'text', text }], isError: true }`, after `onError`. A failure must never read as success to the agent. +- a **returned `Error`** → treated exactly like a throw: `onError` fires, then an `isError` result +- anything else (object/array/number) → JSON-serialized into a text block + +## Reactive & conditional registration + +`name`, `description`, `inputSchema`, `annotations` and `enabled` accept refs or getters. Changing a discoverable field re-registers the tool; toggling `enabled` unregisters and re-registers it. `execute`, `formatOutput` and `onError` are read live at call time, so a changing closure never churns the registration. + +```ts +import { useWebMCP } from '@vueuse/core' +import { shallowRef } from 'vue' + +const signedIn = shallowRef(false) + +useWebMCP({ + name: 'checkout', + description: 'Complete the checkout for the current cart', + enabled: signedIn, // only exposed to agents while signed in + annotations: { readOnlyHint: false }, + execute() { + // … + }, + onError(err) { + console.error('checkout tool failed', err) + }, +}) +``` + +## Registering multiple tools + +Call `useWebMCP` once per tool to register several — each call manages its own registration lifecycle. + +```ts +import { useWebMCP } from '@vueuse/core' + +useWebMCP({ + name: 'add-todo', + description: 'Add a new item to the todo list', + execute({ text }) { + // … + }, +}) + +useWebMCP({ + name: 'clear-todos', + description: 'Remove every item from the todo list', + annotations: { readOnlyHint: false }, + execute() { + // … + }, +}) +``` + +## References + +- [WebMCP explainer & spec (webmachinelearning/webmcp)](https://github.com/webmachinelearning/webmcp) +- [GoogleChromeLabs/use-webmcp-tool](https://github.com/GoogleChromeLabs/use-webmcp-tool) — the React hook this composable is modeled after + +## Type Declarations + +```ts +/** + * A single block of a WebMCP tool result. + * + * @see https://github.com/webmachinelearning/webmcp + */ +export interface WebMCPToolContent { + type: string + text?: string + [key: string]: unknown +} +/** + * The normalized result an agent receives after a tool runs. + */ +export interface WebMCPToolResponse { + content: WebMCPToolContent[] + isError?: boolean +} +/** + * Hints an author can attach to a tool to shape how an agent uses it. + */ +export interface WebMCPToolAnnotations { + /** + * The tool does not mutate state and is safe to call speculatively. + */ + readOnlyHint?: boolean + /** + * The tool may return content that should be treated as untrusted. + */ + untrustedContentHint?: boolean + [key: string]: unknown +} +/** + * The imperative descriptor passed to `document.modelContext.registerTool`. + */ +export interface WebMCPToolDescriptor { + name: string + description: string + inputSchema?: object + annotations?: WebMCPToolAnnotations + execute: (args: any) => Promise | WebMCPToolResponse +} +/** + * The (experimental) imperative WebMCP API surface exposed on `document`. + */ +export interface ModelContext { + registerTool: ( + tool: WebMCPToolDescriptor, + options?: { + signal?: AbortSignal + }, + ) => void +} +export interface UseWebMCPOptions extends ConfigurableDocument { + /** + * Tool identifier the agent uses to invoke this tool. + */ + name: MaybeRefOrGetter + /** + * Natural-language description the agent reads to decide when to call it. + */ + description: MaybeRefOrGetter + /** + * JSON Schema describing the tool arguments. + */ + inputSchema?: MaybeRefOrGetter + /** + * Hints (`readOnlyHint`, `untrustedContentHint`, …) shaping agent behavior. + */ + annotations?: MaybeRefOrGetter + /** + * The function the agent calls. May be async. Its return value is normalized + * into a WebMCP tool result, and any thrown/returned `Error` becomes an + * `isError` result. + */ + execute: (args: Args) => Result | Promise + /** + * Register the tool only while this is `true`. + * + * @default true + */ + enabled?: MaybeRefOrGetter + /** + * Shape the `execute` result before it is normalized into a tool response. + */ + formatOutput?: (result: Result, args: Args) => unknown + /** + * Side effect invoked when `execute` (or `formatOutput`) throws/returns an error. + */ + onError?: (error: unknown) => void +} +export interface UseWebMCPReturn extends Supportable { + /** + * Whether the tool is currently registered with the browser. + */ + isRegistered: ShallowRef + /** + * Registration error, e.g. a `NotAllowedError` from a `tools` permissions policy. + */ + error: ShallowRef +} +/** + * Register a [WebMCP](https://github.com/webmachinelearning/webmcp) tool and + * tie its lifecycle to the current scope. + * + * The tool is registered when the composable runs (and whenever a discoverable + * part — `name`, `description`, `inputSchema`, `annotations` or `enabled` — + * changes) and unregistered automatically on scope dispose, so the tools an + * agent sees stay in lockstep with what is on screen. Call it multiple times to + * register multiple tools. + * + * The API is experimental (`document.modelContext`), so this feature-detects + * and degrades to a no-op wherever it is absent. + * + * @see https://vueuse.org/useWebMCP + * @see https://github.com/webmachinelearning/webmcp + */ +export declare function useWebMCP, Result = unknown>( + options: UseWebMCPOptions, +): UseWebMCPReturn +``` diff --git a/plugins/vueuse/agent/skills/vueuse-functions/references/useWebSocket.md b/plugins/vueuse/agent/skills/vueuse-functions/references/useWebSocket.md index 1344eedc..960d9157 100644 --- a/plugins/vueuse/agent/skills/vueuse-functions/references/useWebSocket.md +++ b/plugins/vueuse/agent/skills/vueuse-functions/references/useWebSocket.md @@ -186,13 +186,6 @@ export interface UseWebSocketOptions { * Response message for the heartbeat, if undefined the message will be used */ responseMessage?: MaybeRefOrGetter - /** - * Interval, in milliseconds - * - * @deprecated Please use `scheduler` option instead - * @default 1000 - */ - interval?: number /** * Heartbeat response timeout, in milliseconds * diff --git a/plugins/vueuse/agent/skills/vueuse-functions/references/watchIgnorable.md b/plugins/vueuse/agent/skills/vueuse-functions/references/watchIgnorable.md index 786532b2..ac5d6df4 100644 --- a/plugins/vueuse/agent/skills/vueuse-functions/references/watchIgnorable.md +++ b/plugins/vueuse/agent/skills/vueuse-functions/references/watchIgnorable.md @@ -79,7 +79,7 @@ await nextTick() // logs: Changed to after! ## Recommended Readings -- [Ignorable Watch](https://patak.dev/vue/ignorable-watch.html) - by [@patak-dev](https://github.com/patak-dev) +- [Ignorable Watch](https://patak.dev/vue/ignorable-watch.html) - by [@patak-cat](https://github.com/patak-cat) ## Type Declarations diff --git a/plugins/vueuse/skills-lock.json b/plugins/vueuse/skills-lock.json index f8d43598..a0aa4c29 100644 --- a/plugins/vueuse/skills-lock.json +++ b/plugins/vueuse/skills-lock.json @@ -5,7 +5,7 @@ "source": "vueuse/skills", "sourceType": "github", "skillPath": "skills/vueuse-functions/SKILL.md", - "computedHash": "665497ecb63a43cef76fafcd1d5b7ec85311060d628452f40f9f9c4114157a83" + "computedHash": "70b65fb127323568380de490290eaf195b165da23c1f4fa27df10b386ca0dab2" } } }